changeset 13357:f9fbf8954d7d

Added qtermwidget files.
author Jacob Dawid <jacob.dawid@googlemail.com>
date Thu, 07 Apr 2011 12:05:04 +0200
parents 6c374a610e99
children d9f1bed01bd0
files gui//AUTHORS gui//BlockArray.cpp gui//BlockArray.h gui//COPYING gui//Changelog gui//Character.h gui//CharacterColor.h gui//ColorTables.h gui//DefaultTranslatorText.h gui//Emulation.cpp gui//Emulation.h gui//ExtendedDefaultTranslator.h gui//Filter.cpp gui//Filter.h gui//History.cpp gui//History.h gui//KeyboardTranslator.cpp gui//KeyboardTranslator.h gui//LineFont.h gui//LineFont.src gui//Makefile gui//Pty.cpp gui//Pty.h gui//Quint gui//Screen.cpp gui//Screen.h gui//ScreenWindow.cpp gui//ScreenWindow.h gui//Session.cpp gui//Session.h gui//ShellCommand.cpp gui//ShellCommand.h gui//TODO gui//TerminalCharacterDecoder.cpp gui//TerminalCharacterDecoder.h gui//TerminalDisplay.cpp gui//TerminalDisplay.h gui//Vt102Emulation.cpp gui//Vt102Emulation.h gui//default.keytab gui//k3process.cpp gui//k3process.h gui//k3processcontroller.cpp gui//k3processcontroller.h gui//kb-layouts/CVS/Entries gui//kb-layouts/CVS/Repository gui//kb-layouts/CVS/Root gui//kb-layouts/default.keytab gui//kb-layouts/linux.keytab gui//kb-layouts/vt420pc.keytab gui//konsole_wcwidth.cpp gui//konsole_wcwidth.h gui//kpty.cpp gui//kpty.h gui//kpty_p.h gui//lib.pro gui//qtermwidget.cpp gui//qtermwidget.h
diffstat 58 files changed, 22334 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
new file mode 100644
--- /dev/null
+++ b/gui//AUTHORS
@@ -0,0 +1,1 @@
+e_k@users.sourceforge.net
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/gui//BlockArray.cpp
@@ -0,0 +1,337 @@
+/*
+    This file is part of Konsole, an X terminal.
+    Copyright (C) 2000 by Stephan Kulow <coolo@kde.org>
+
+    Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301  USA.
+
+*/
+
+// Own
+#include "BlockArray.h"
+
+#include <QtCore>
+
+// System
+#include <assert.h>
+#include <sys/mman.h>
+#include <sys/param.h>
+#include <unistd.h>
+#include <stdio.h>
+
+
+using namespace Konsole;
+
+static int blocksize = 0;
+
+BlockArray::BlockArray()
+    : size(0),
+      current(size_t(-1)),
+      index(size_t(-1)),
+      lastmap(0),
+      lastmap_index(size_t(-1)),
+      lastblock(0), ion(-1),
+      length(0)
+{
+    // lastmap_index = index = current = size_t(-1);
+    if (blocksize == 0)
+        blocksize = ((sizeof(Block) / getpagesize()) + 1) * getpagesize();
+
+}
+
+BlockArray::~BlockArray()
+{
+    setHistorySize(0);
+    assert(!lastblock);
+}
+
+size_t BlockArray::append(Block *block)
+{
+    if (!size)
+        return size_t(-1);
+
+    ++current;
+    if (current >= size) current = 0;
+
+    int rc;
+    rc = lseek(ion, current * blocksize, SEEK_SET); if (rc < 0) { perror("HistoryBuffer::add.seek"); setHistorySize(0); return size_t(-1); }
+    rc = write(ion, block, blocksize); if (rc < 0) { perror("HistoryBuffer::add.write"); setHistorySize(0); return size_t(-1); }
+
+    length++;
+    if (length > size) length = size;
+
+    ++index;
+
+    delete block;
+    return current;
+}
+
+size_t BlockArray::newBlock()
+{
+    if (!size)
+        return size_t(-1);
+    append(lastblock);
+
+    lastblock = new Block();
+    return index + 1;
+}
+
+Block *BlockArray::lastBlock() const
+{
+    return lastblock;
+}
+
+bool BlockArray::has(size_t i) const
+{
+    if (i == index + 1)
+        return true;
+
+    if (i > index)
+        return false;
+    if (index - i >= length)
+        return false;
+    return true;
+}
+
+const Block* BlockArray::at(size_t i)
+{
+    if (i == index + 1)
+        return lastblock;
+
+    if (i == lastmap_index)
+        return lastmap;
+
+    if (i > index) {
+        qDebug() << "BlockArray::at() i > index\n";
+        return 0;
+    }
+    
+//     if (index - i >= length) {
+//         kDebug(1211) << "BlockArray::at() index - i >= length\n";
+//         return 0;
+//     }
+
+    size_t j = i; // (current - (index - i) + (index/size+1)*size) % size ;
+
+    assert(j < size);
+    unmap();
+
+    Block *block = (Block*)mmap(0, blocksize, PROT_READ, MAP_PRIVATE, ion, j * blocksize);
+
+    if (block == (Block*)-1) { perror("mmap"); return 0; }
+
+    lastmap = block;
+    lastmap_index = i;
+
+    return block;
+}
+
+void BlockArray::unmap()
+{
+    if (lastmap) {
+        int res = munmap((char*)lastmap, blocksize);
+        if (res < 0) perror("munmap");
+    }
+    lastmap = 0;
+    lastmap_index = size_t(-1);
+}
+
+bool BlockArray::setSize(size_t newsize)
+{
+    return setHistorySize(newsize * 1024 / blocksize);
+}
+
+bool BlockArray::setHistorySize(size_t newsize)
+{
+//    kDebug(1211) << "setHistorySize " << size << " " << newsize;
+
+    if (size == newsize)
+        return false;
+
+    unmap();
+
+    if (!newsize) {
+        delete lastblock;
+        lastblock = 0;
+        if (ion >= 0) close(ion);
+        ion = -1;
+        current = size_t(-1);
+        return true;
+    }
+
+    if (!size) {
+        FILE* tmp = tmpfile();
+        if (!tmp) {
+            perror("konsole: cannot open temp file.\n");
+        } else {
+            ion = dup(fileno(tmp));
+            if (ion<0) {
+                perror("konsole: cannot dup temp file.\n");
+                fclose(tmp);
+            }
+        }
+        if (ion < 0)
+            return false;
+
+        assert(!lastblock);
+
+        lastblock = new Block();
+        size = newsize;
+        return false;
+    }
+
+    if (newsize > size) {
+        increaseBuffer();
+        size = newsize;
+        return false;
+    } else {
+        decreaseBuffer(newsize);
+        ftruncate(ion, length*blocksize);
+        size = newsize;
+
+        return true;
+    }
+}
+
+void moveBlock(FILE *fion, int cursor, int newpos, char *buffer2)
+{
+    int res = fseek(fion, cursor * blocksize, SEEK_SET);
+    if (res)
+        perror("fseek");
+    res = fread(buffer2, blocksize, 1, fion);
+    if (res != 1)
+        perror("fread");
+
+    res = fseek(fion, newpos * blocksize, SEEK_SET);
+    if (res)
+        perror("fseek");
+    res = fwrite(buffer2, blocksize, 1, fion);
+    if (res != 1)
+        perror("fwrite");
+    //    printf("moving block %d to %d\n", cursor, newpos);
+}
+
+void BlockArray::decreaseBuffer(size_t newsize)
+{
+    if (index < newsize) // still fits in whole
+        return;
+
+    int offset = (current - (newsize - 1) + size) % size;
+
+    if (!offset)
+        return;
+
+    // The Block constructor could do somthing in future...
+    char *buffer1 = new char[blocksize];
+
+    FILE *fion = fdopen(dup(ion), "w+b");
+    if (!fion) {
+        delete [] buffer1;
+        perror("fdopen/dup");
+        return;
+    }
+
+    int firstblock;
+    if (current <= newsize) {
+        firstblock = current + 1;
+    } else {
+        firstblock = 0;
+    }
+
+    size_t oldpos;
+    for (size_t i = 0, cursor=firstblock; i < newsize; i++) {
+        oldpos = (size + cursor + offset) % size;
+        moveBlock(fion, oldpos, cursor, buffer1);
+        if (oldpos < newsize) {
+            cursor = oldpos;
+        } else
+            cursor++;
+    }
+
+    current = newsize - 1;
+    length = newsize;
+
+    delete [] buffer1;
+
+    fclose(fion);
+
+}
+
+void BlockArray::increaseBuffer()
+{
+    if (index < size) // not even wrapped once
+        return;
+
+    int offset = (current + size + 1) % size;
+    if (!offset) // no moving needed
+        return;
+
+    // The Block constructor could do somthing in future...
+    char *buffer1 = new char[blocksize];
+    char *buffer2 = new char[blocksize];
+
+    int runs = 1;
+    int bpr = size; // blocks per run
+
+    if (size % offset == 0) {
+        bpr = size / offset;
+        runs = offset;
+    }
+
+    FILE *fion = fdopen(dup(ion), "w+b");
+    if (!fion) {
+        perror("fdopen/dup");
+	delete [] buffer1;
+	delete [] buffer2;
+        return;
+    }
+
+    int res;
+    for (int i = 0; i < runs; i++)
+    {
+        // free one block in chain
+        int firstblock = (offset + i) % size;
+        res = fseek(fion, firstblock * blocksize, SEEK_SET);
+        if (res)
+            perror("fseek");
+        res = fread(buffer1, blocksize, 1, fion);
+        if (res != 1)
+            perror("fread");
+        int newpos = 0;
+        for (int j = 1, cursor=firstblock; j < bpr; j++)
+        {
+            cursor = (cursor + offset) % size;
+            newpos = (cursor - offset + size) % size;
+            moveBlock(fion, cursor, newpos, buffer2);
+        }
+        res = fseek(fion, i * blocksize, SEEK_SET);
+        if (res)
+            perror("fseek");
+        res = fwrite(buffer1, blocksize, 1, fion);
+        if (res != 1)
+            perror("fwrite");
+    }
+    current = size - 1;
+    length = size;
+
+    delete [] buffer1;
+    delete [] buffer2;
+
+    fclose(fion);
+
+}
+
new file mode 100644
--- /dev/null
+++ b/gui//BlockArray.h
@@ -0,0 +1,125 @@
+/*
+    This file is part of Konsole, an X terminal.
+    Copyright (C) 2000 by Stephan Kulow <coolo@kde.org>
+   
+    Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301  USA.
+*/
+
+#ifndef BLOCKARRAY_H
+#define BLOCKARRAY_H
+
+#include <unistd.h>
+
+//#error Do not use in KDE 2.1
+
+#define BlockSize (1 << 12)
+#define ENTRIES   ((BlockSize - sizeof(size_t) ) / sizeof(unsigned char))
+
+namespace Konsole
+{
+
+struct Block {
+    Block() { size = 0; }
+    unsigned char data[ENTRIES];
+    size_t size;
+};
+
+// ///////////////////////////////////////////////////////
+
+class BlockArray {
+public:
+    /**
+    * Creates a history file for holding
+    * maximal size blocks. If more blocks
+    * are requested, then it drops earlier
+    * added ones.
+    */
+    BlockArray();
+
+    /// destructor
+    ~BlockArray();
+
+    /**
+    * adds the Block at the end of history.
+    * This may drop other blocks.
+    *
+    * The ownership on the block is transfered.
+    * An unique index number is returned for accessing
+    * it later (if not yet dropped then)
+    *
+    * Note, that the block may be dropped completely
+    * if history is turned off.
+    */
+    size_t append(Block *block);
+
+    /**
+    * gets the block at the index. Function may return
+    * 0 if the block isn't available any more.
+    *
+    * The returned block is strictly readonly as only
+    * maped in memory - and will be invalid on the next
+    * operation on this class.
+    */
+    const Block *at(size_t index);
+
+    /**
+    * reorders blocks as needed. If newsize is null,
+    * the history is emptied completely. The indices
+    * returned on append won't change their semantic,
+    * but they may not be valid after this call.
+    */
+    bool setHistorySize(size_t newsize);
+
+    size_t newBlock();
+
+    Block *lastBlock() const;
+
+    /**
+    * Convenient function to set the size in KBytes
+    * instead of blocks
+    */
+    bool setSize(size_t newsize);
+
+    size_t len() const { return length; }
+
+    bool has(size_t index) const;
+
+    size_t getCurrent() const { return current; }
+
+private:
+    void unmap();
+    void increaseBuffer();
+    void decreaseBuffer(size_t newsize);
+
+    size_t size;
+    // current always shows to the last inserted block
+    size_t current;
+    size_t index;
+
+    Block *lastmap;
+    size_t lastmap_index;
+    Block *lastblock;
+
+    int ion;
+    size_t length;
+
+};
+
+}
+
+#endif
new file mode 100644
--- /dev/null
+++ b/gui//COPYING
@@ -0,0 +1,340 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
new file mode 100644
--- /dev/null
+++ b/gui//Changelog
@@ -0,0 +1,19 @@
+31.07.2008
+Interface class from c-style conversions rewritten with pimpl support.
+
+
+16.07.2008 
+Added optional scrollbar 
+
+
+06.06.2008 
+Some artefacts were removed, some added...
+Also added support for color schemes, and 3 color schemes provided (classical - white on black, green on black, black on light yellow). Is it enough or not? 
+
+
+26.05.2008 
+Added file release as an archive with source code. But preferrable way is still getting code from CVS, cause file release can be outdated. 
+
+
+11.05.2008 
+Initial CVS import - first version comes with number 0.0.1
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/gui//Character.h
@@ -0,0 +1,210 @@
+/*
+    This file is part of Konsole, KDE's terminal.
+    
+    Copyright (C) 2007 by Robert Knight <robertknight@gmail.com>
+    Copyright (C) 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
+
+    Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301  USA.
+*/
+
+#ifndef CHARACTER_H
+#define CHARACTER_H
+
+// Qt
+#include <QtCore/QHash>
+
+// Local
+#include "CharacterColor.h"
+
+namespace Konsole
+{
+
+typedef unsigned char LineProperty;
+
+static const int LINE_DEFAULT		= 0;
+static const int LINE_WRAPPED 	 	= (1 << 0);
+static const int LINE_DOUBLEWIDTH  	= (1 << 1);
+static const int LINE_DOUBLEHEIGHT	= (1 << 2);
+
+#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
+#define RE_CURSOR          (1 << 4)
+#define RE_EXTENDED_CHAR   (1 << 5)
+
+/**
+ * A single character in the terminal which consists of a unicode character
+ * value, foreground and background colors and a set of rendition attributes
+ * which specify how it should be drawn.
+ */
+class Character
+{
+public:
+  /** 
+   * Constructs a new character.
+   *
+   * @param _c The unicode character value of this character.
+   * @param _f The foreground color used to draw the character.
+   * @param _b The color used to draw the character's background.
+   * @param _r A set of rendition flags which specify how this character is to be drawn.
+   */
+  inline Character(quint16 _c = ' ',
+            CharacterColor  _f = CharacterColor(COLOR_SPACE_DEFAULT,DEFAULT_FORE_COLOR),
+            CharacterColor  _b = CharacterColor(COLOR_SPACE_DEFAULT,DEFAULT_BACK_COLOR),
+            quint8  _r = DEFAULT_RENDITION)
+       : character(_c), rendition(_r), foregroundColor(_f), backgroundColor(_b) {}
+
+  union
+  {
+    /** The unicode character value for this character. */
+    quint16 character;
+    /** 
+     * Experimental addition which allows a single Character instance to contain more than
+     * one unicode character.
+     *
+     * charSequence is a hash code which can be used to look up the unicode
+     * character sequence in the ExtendedCharTable used to create the sequence.
+     */
+    quint16 charSequence; 
+  };
+
+  /** A combination of RENDITION flags which specify options for drawing the character. */
+  quint8  rendition;
+
+  /** The foreground color used to draw this character. */
+  CharacterColor  foregroundColor; 
+  /** The color used to draw this character's background. */
+  CharacterColor  backgroundColor;
+
+  /** 
+   * Returns true if this character has a transparent background when
+   * it is drawn with the specified @p palette.
+   */
+  bool   isTransparent(const ColorEntry* palette) const;
+  /**
+   * Returns true if this character should always be drawn in bold when
+   * it is drawn with the specified @p palette, independent of whether
+   * or not the character has the RE_BOLD rendition flag. 
+   */
+  bool   isBold(const ColorEntry* base) const;
+  
+  /** 
+   * Compares two characters and returns true if they have the same unicode character value,
+   * rendition and colors.
+   */
+  friend bool operator == (const Character& a, const Character& b);
+  /**
+   * Compares two characters and returns true if they have different unicode character values,
+   * renditions or colors.
+   */
+  friend bool operator != (const Character& a, const Character& b);
+};
+
+inline bool operator == (const Character& a, const Character& b)
+{ 
+  return a.character == b.character && 
+         a.rendition == b.rendition && 
+         a.foregroundColor == b.foregroundColor && 
+         a.backgroundColor == b.backgroundColor;
+}
+
+inline bool operator != (const Character& a, const Character& b)
+{
+  return    a.character != b.character || 
+            a.rendition != b.rendition || 
+            a.foregroundColor != b.foregroundColor || 
+            a.backgroundColor != b.backgroundColor;
+}
+
+inline bool Character::isTransparent(const ColorEntry* base) const
+{
+  return ((backgroundColor._colorSpace == COLOR_SPACE_DEFAULT) && 
+          base[backgroundColor._u+0+(backgroundColor._v?BASE_COLORS:0)].transparent)
+      || ((backgroundColor._colorSpace == COLOR_SPACE_SYSTEM) && 
+          base[backgroundColor._u+2+(backgroundColor._v?BASE_COLORS:0)].transparent);
+}
+
+inline bool Character::isBold(const ColorEntry* base) const
+{
+  return ((backgroundColor._colorSpace == COLOR_SPACE_DEFAULT) &&
+            base[backgroundColor._u+0+(backgroundColor._v?BASE_COLORS:0)].bold)
+      || ((backgroundColor._colorSpace == COLOR_SPACE_SYSTEM) &&
+            base[backgroundColor._u+2+(backgroundColor._v?BASE_COLORS:0)].bold);
+}
+
+extern unsigned short vt100_graphics[32];
+
+
+/**
+ * A table which stores sequences of unicode characters, referenced
+ * by hash keys.  The hash key itself is the same size as a unicode
+ * character ( ushort ) so that it can occupy the same space in
+ * a structure.
+ */
+class ExtendedCharTable
+{
+public:
+    /** Constructs a new character table. */
+    ExtendedCharTable();
+    ~ExtendedCharTable();
+
+    /**
+     * Adds a sequences of unicode characters to the table and returns
+     * a hash code which can be used later to look up the sequence
+     * using lookupExtendedChar()
+     *
+     * If the same sequence already exists in the table, the hash
+     * of the existing sequence will be returned.
+     *
+     * @param unicodePoints An array of unicode character points
+     * @param length Length of @p unicodePoints
+     */
+    ushort createExtendedChar(ushort* unicodePoints , ushort length);
+    /**
+     * Looks up and returns a pointer to a sequence of unicode characters
+     * which was added to the table using createExtendedChar().
+     *
+     * @param hash The hash key returned by createExtendedChar()
+     * @param length This variable is set to the length of the 
+     * character sequence.
+     *
+     * @return A unicode character sequence of size @p length.
+     */
+    ushort* lookupExtendedChar(ushort hash , ushort& length) const;
+
+    /** The global ExtendedCharTable instance. */
+    static ExtendedCharTable instance;
+private:
+    // calculates the hash key of a sequence of unicode points of size 'length'
+    ushort extendedCharHash(ushort* unicodePoints , ushort length) const;
+    // tests whether the entry in the table specified by 'hash' matches the 
+    // character sequence 'unicodePoints' of size 'length'
+    bool extendedCharMatch(ushort hash , ushort* unicodePoints , ushort length) const;
+    // internal, maps hash keys to character sequence buffers.  The first ushort
+    // in each value is the length of the buffer, followed by the ushorts in the buffer
+    // themselves.
+    QHash<ushort,ushort*> extendedCharTable;
+};
+
+}
+
+#endif // CHARACTER_H
+
new file mode 100644
--- /dev/null
+++ b/gui//CharacterColor.h
@@ -0,0 +1,301 @@
+/*
+    This file is part of Konsole, KDE's terminal.
+    
+    Copyright (C) 2007 by Robert Knight <robertknight@gmail.com>
+    Copyright (C) 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
+
+    Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301  USA.
+*/
+
+#ifndef CHARACTERCOLOR_H
+#define CHARACTERCOLOR_H
+
+// Qt
+#include <QtGui/QColor>
+
+namespace Konsole
+{
+
+/** 
+ * An entry in a terminal display's color palette. 
+ *
+ * A color palette is an array of 16 ColorEntry instances which map
+ * system color indexes (from 0 to 15) into actual colors.
+ *
+ * Each entry can be set as bold, in which case any text
+ * drawn using the color should be drawn in bold.  
+ *
+ * Each entry can also be transparent, in which case the terminal
+ * display should avoid drawing the background for any characters
+ * using the entry as a background.
+ */
+class ColorEntry
+{
+public:
+  /** 
+   * Constructs a new color palette entry.
+   *
+   * @param c The color value for this entry.
+   * @param tr Specifies that the color should be transparent when used as a background color.
+   * @param b Specifies that text drawn with this color should be bold.
+   */
+  ColorEntry(QColor c, bool tr, bool b) : color(c), transparent(tr), bold(b) {}
+
+  /**
+   * Constructs a new color palette entry with an undefined color, and
+   * with the transparent and bold flags set to false.
+   */ 
+  ColorEntry() : transparent(false), bold(false) {} 
+ 
+  /**
+   * Sets the color, transparency and boldness of this color to those of @p rhs.
+   */ 
+  void operator=(const ColorEntry& rhs) 
+  { 
+       color = rhs.color; 
+       transparent = rhs.transparent; 
+       bold = rhs.bold; 
+  }
+
+  /** The color value of this entry for display. */
+  QColor color;
+
+  /** 
+   * If true character backgrounds using this color should be transparent. 
+   * This is not applicable when the color is used to render text.
+   */
+  bool   transparent;
+  /**
+   * If true characters drawn using this color should be bold.
+   * This is not applicable when the color is used to draw a character's background.
+   */
+  bool   bold;        
+};
+
+
+// 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
+
+//a standard set of colors using black text on a white background.
+//defined in TerminalDisplay.cpp
+
+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 )
+};
+
+/* CharacterColor is a union of the various color spaces.
+
+   Assignment is as follows:
+
+   Type  - Space        - Values
+
+   0     - Undefined   - u:  0,      v:0        w:0
+   1     - Default     - u:  0..1    v:intense  w:0
+   2     - System      - u:  0..7    v:intense  w:0
+   3     - Index(256)  - u: 16..255  v:0        w:0
+   4     - RGB         - u:  0..255  v:0..256   w:0..256
+
+   Default colour space has two separate colours, namely
+   default foreground and default background colour.
+*/
+
+#define COLOR_SPACE_UNDEFINED   0
+#define COLOR_SPACE_DEFAULT     1
+#define COLOR_SPACE_SYSTEM      2
+#define COLOR_SPACE_256         3
+#define COLOR_SPACE_RGB         4
+
+/**
+ * Describes the color of a single character in the terminal.
+ */
+class CharacterColor
+{
+    friend class Character;
+
+public:
+  /** Constructs a new CharacterColor whoose color and color space are undefined. */
+  CharacterColor() 
+      : _colorSpace(COLOR_SPACE_UNDEFINED), 
+        _u(0), 
+        _v(0), 
+        _w(0) 
+  {}
+
+  /** 
+   * Constructs a new CharacterColor using the specified @p colorSpace and with 
+   * color value @p co
+   *
+   * The meaning of @p co depends on the @p colorSpace used.
+   *
+   * TODO : Document how @p co relates to @p colorSpace
+   *
+   * TODO : Add documentation about available color spaces.
+   */
+  CharacterColor(quint8 colorSpace, int co) 
+      : _colorSpace(colorSpace), 
+        _u(0), 
+        _v(0), 
+        _w(0)
+  {
+    switch (colorSpace)
+    {
+        case COLOR_SPACE_DEFAULT:
+            _u = co & 1;
+            break;
+        case COLOR_SPACE_SYSTEM:
+            _u = co & 7;
+            _v = (co >> 3) & 1;
+            break;
+        case COLOR_SPACE_256:  
+            _u = co & 255;
+            break;
+        case COLOR_SPACE_RGB:
+            _u = co >> 16;
+            _v = co >> 8;
+            _w = co;
+            break;
+        default:
+            _colorSpace = COLOR_SPACE_UNDEFINED;
+    }
+  }
+
+  /** 
+   * Returns true if this character color entry is valid.
+   */
+  bool isValid() 
+  {
+        return _colorSpace != COLOR_SPACE_UNDEFINED;
+  }
+    
+  /** 
+   * Toggles the value of this color between a normal system color and the corresponding intensive
+   * system color.
+   * 
+   * This is only applicable if the color is using the COLOR_SPACE_DEFAULT or COLOR_SPACE_SYSTEM
+   * color spaces.
+   */
+  void toggleIntensive();
+
+  /** 
+   * Returns the color within the specified color @palette
+   *
+   * The @p palette is only used if this color is one of the 16 system colors, otherwise
+   * it is ignored.
+   */
+  QColor color(const ColorEntry* palette) const;
+ 
+  /** 
+   * Compares two colors and returns true if they represent the same color value and
+   * use the same color space.
+   */
+  friend bool operator == (const CharacterColor& a, const CharacterColor& b);
+  /**
+   * Compares two colors and returns true if they represent different color values
+   * or use different color spaces.
+   */
+  friend bool operator != (const CharacterColor& a, const CharacterColor& b);
+
+private:
+  quint8 _colorSpace;
+
+  // bytes storing the character color 
+  quint8 _u; 
+  quint8 _v; 
+  quint8 _w; 
+};
+
+inline bool operator == (const CharacterColor& a, const CharacterColor& b)
+{ 
+  return *reinterpret_cast<const quint32*>(&a._colorSpace) == 
+         *reinterpret_cast<const quint32*>(&b._colorSpace);
+}
+
+inline bool operator != (const CharacterColor& a, const CharacterColor& b)
+{
+  return *reinterpret_cast<const quint32*>(&a._colorSpace) != 
+         *reinterpret_cast<const quint32*>(&b._colorSpace);
+}
+
+inline const QColor color256(quint8 u, const ColorEntry* base)
+{
+  //   0.. 16: system colors
+  if (u <   8) return base[u+2            ].color; u -= 8;
+  if (u <   8) return base[u+2+BASE_COLORS].color; u -= 8;
+
+  //  16..231: 6x6x6 rgb color cube
+  if (u < 216) return QColor(255*((u/36)%6)/5,
+                             255*((u/ 6)%6)/5,
+                             255*((u/ 1)%6)/5); u -= 216;
+  
+  // 232..255: gray, leaving out black and white
+  int gray = u*10+8; return QColor(gray,gray,gray);
+}
+
+inline QColor CharacterColor::color(const ColorEntry* base) const
+{
+  switch (_colorSpace)
+  {
+    case COLOR_SPACE_DEFAULT: return base[_u+0+(_v?BASE_COLORS:0)].color;
+    case COLOR_SPACE_SYSTEM: return base[_u+2+(_v?BASE_COLORS:0)].color;
+    case COLOR_SPACE_256: return color256(_u,base);
+    case COLOR_SPACE_RGB: return QColor(_u,_v,_w);
+    case COLOR_SPACE_UNDEFINED: return QColor();
+  }
+
+  Q_ASSERT(false); // invalid color space
+
+  return QColor();
+}
+
+inline void CharacterColor::toggleIntensive()
+{
+  if (_colorSpace == COLOR_SPACE_SYSTEM || _colorSpace == COLOR_SPACE_DEFAULT)
+  {
+    _v = !_v;
+  }
+}
+
+
+}
+
+#endif // CHARACTERCOLOR_H
+
new file mode 100644
--- /dev/null
+++ b/gui//ColorTables.h
@@ -0,0 +1,58 @@
+#ifndef _COLOR_TABLE_H
+#define _COLOR_TABLE_H
+
+#include "CharacterColor.h"
+
+using namespace Konsole;
+
+static const ColorEntry whiteonblack_color_table[TABLE_COLORS] =
+{
+    // normal
+    ColorEntry(QColor(0xFF,0xFF,0xFF), 0, 0 ), ColorEntry( QColor(0x00,0x00,0x00), 1, 0 ), // Dfore, Dback
+    ColorEntry(QColor(0x00,0x00,0x00), 0, 0 ), ColorEntry( QColor(0xB2,0x18,0x18), 0, 0 ), // Black, Red
+    ColorEntry(QColor(0x18,0xB2,0x18), 0, 0 ), ColorEntry( QColor(0xB2,0x68,0x18), 0, 0 ), // Green, Yellow
+    ColorEntry(QColor(0x18,0x18,0xB2), 0, 0 ), ColorEntry( QColor(0xB2,0x18,0xB2), 0, 0 ), // Blue, Magenta
+    ColorEntry(QColor(0x18,0xB2,0xB2), 0, 0 ), ColorEntry( QColor(0xB2,0xB2,0xB2), 0, 0 ), // Cyan, White
+    // intensiv
+    ColorEntry(QColor(0x00,0x00,0x00), 0, 1 ), ColorEntry( QColor(0xFF,0xFF,0xFF), 1, 0 ),
+    ColorEntry(QColor(0x68,0x68,0x68), 0, 0 ), ColorEntry( QColor(0xFF,0x54,0x54), 0, 0 ),
+    ColorEntry(QColor(0x54,0xFF,0x54), 0, 0 ), ColorEntry( QColor(0xFF,0xFF,0x54), 0, 0 ),
+    ColorEntry(QColor(0x54,0x54,0xFF), 0, 0 ), ColorEntry( QColor(0xFF,0x54,0xFF), 0, 0 ),
+    ColorEntry(QColor(0x54,0xFF,0xFF), 0, 0 ), ColorEntry( QColor(0xFF,0xFF,0xFF), 0, 0 )
+};
+
+static const ColorEntry greenonblack_color_table[TABLE_COLORS] =
+{
+    ColorEntry(QColor(    24, 240,  24),  0, 0), ColorEntry(QColor(     0,   0,   0),  1, 0),  
+    ColorEntry(QColor(     0,   0,   0),  0, 0), ColorEntry(QColor(   178,  24,  24),  0, 0), 
+    ColorEntry(QColor(    24, 178,  24),  0, 0), ColorEntry(QColor(   178, 104,  24),  0, 0), 
+    ColorEntry(QColor(    24,  24, 178),  0, 0), ColorEntry(QColor(   178,  24, 178),  0, 0), 
+    ColorEntry(QColor(    24, 178, 178),  0, 0), ColorEntry(QColor(   178, 178, 178),  0, 0), 
+    // intensive colors
+    ColorEntry(QColor(   24, 240,  24),  0, 1 ), ColorEntry(QColor(    0,   0,   0),  1, 0 ),
+    ColorEntry(QColor(  104, 104, 104),  0, 0 ), ColorEntry(QColor(  255,  84,  84),  0, 0 ),
+    ColorEntry(QColor(   84, 255,  84),  0, 0 ), ColorEntry(QColor(  255, 255,  84),  0, 0 ),
+    ColorEntry(QColor(   84,  84, 255),  0, 0 ), ColorEntry(QColor(  255,  84, 255),  0, 0 ),
+    ColorEntry(QColor(   84, 255, 255),  0, 0 ), ColorEntry(QColor(  255, 255, 255),  0, 0 )
+};
+
+static const ColorEntry blackonlightyellow_color_table[TABLE_COLORS] = 
+{
+    ColorEntry(QColor(  0,   0,   0),  0, 0),  ColorEntry(QColor( 255, 255, 221),  1, 0),  
+    ColorEntry(QColor(  0,   0,   0),  0, 0),  ColorEntry(QColor( 178,  24,  24),  0, 0),  
+    ColorEntry(QColor( 24, 178,  24),  0, 0),  ColorEntry(QColor( 178, 104,  24),  0, 0),  
+    ColorEntry(QColor( 24,  24, 178),  0, 0),  ColorEntry(QColor( 178,  24, 178),  0, 0),  
+    ColorEntry(QColor( 24, 178, 178),  0, 0),  ColorEntry(QColor( 178, 178, 178),  0, 0),  
+    ColorEntry(QColor(  0,   0,   0),  0, 1),  ColorEntry(QColor( 255, 255, 221),  1, 0),  
+    ColorEntry(QColor(104, 104, 104),  0, 0),  ColorEntry(QColor( 255,  84,  84),  0, 0),  
+    ColorEntry(QColor( 84, 255,  84),  0, 0),  ColorEntry(QColor( 255, 255,  84),  0, 0),  
+    ColorEntry(QColor( 84,  84, 255),  0, 0),  ColorEntry(QColor( 255,  84, 255),  0, 0),  
+    ColorEntry(QColor( 84, 255, 255),  0, 0),  ColorEntry(QColor( 255, 255, 255),  0, 0)
+};
+ 			  
+			  
+			  
+
+
+#endif
+
new file mode 100644
--- /dev/null
+++ b/gui//DefaultTranslatorText.h
@@ -0,0 +1,2 @@
+"keyboard \"Fallback Key Translator\"\n"
+"key Tab : \"\\t\" \0"
new file mode 100644
--- /dev/null
+++ b/gui//Emulation.cpp
@@ -0,0 +1,543 @@
+/*
+    This file is part of Konsole, an X terminal.
+
+    Copyright (C) 2007 Robert Knight <robertknight@gmail.com> 
+    Copyright (C) 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
+    Copyright (C) 1996 by Matthias Ettrich <ettrich@kde.org>
+
+    Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301  USA.
+*/
+
+// Own
+#include "Emulation.h"
+
+// System
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+// Qt
+#include <QtGui/QApplication>
+#include <QtGui/QClipboard>
+#include <QtCore/QHash>
+#include <QtGui/QKeyEvent>
+#include <QtCore/QRegExp>
+#include <QtCore/QTextStream>
+#include <QtCore/QThread>
+
+#include <QtCore/QTime>
+
+// Konsole
+#include "KeyboardTranslator.h"
+#include "Screen.h"
+#include "TerminalCharacterDecoder.h"
+#include "ScreenWindow.h"
+
+using namespace Konsole;
+
+/* ------------------------------------------------------------------------- */
+/*                                                                           */
+/*                               Emulation                                  */
+/*                                                                           */
+/* ------------------------------------------------------------------------- */
+
+//#define CNTL(c) ((c)-'@')
+
+/*!
+*/
+
+Emulation::Emulation() :
+  _currentScreen(0),
+  _codec(0),
+  _decoder(0),
+  _keyTranslator(0),
+  _usesMouse(false)
+{
+
+  // create screens with a default size
+  _screen[0] = new Screen(40,80);
+  _screen[1] = new Screen(40,80);
+  _currentScreen = _screen[0];
+
+  QObject::connect(&_bulkTimer1, SIGNAL(timeout()), this, SLOT(showBulk()) );
+  QObject::connect(&_bulkTimer2, SIGNAL(timeout()), this, SLOT(showBulk()) );
+   
+  // listen for mouse status changes
+  connect( this , SIGNAL(programUsesMouseChanged(bool)) , 
+           SLOT(usesMouseChanged(bool)) );
+}
+
+bool Emulation::programUsesMouse() const
+{
+    return _usesMouse;
+}
+
+void Emulation::usesMouseChanged(bool usesMouse)
+{
+    _usesMouse = usesMouse;
+}
+
+ScreenWindow* Emulation::createWindow()
+{
+    ScreenWindow* window = new ScreenWindow();
+    window->setScreen(_currentScreen);
+    _windows << window;
+
+    connect(window , SIGNAL(selectionChanged()),
+            this , SLOT(bufferedUpdate()));
+
+    connect(this , SIGNAL(outputChanged()),
+            window , SLOT(notifyOutputChanged()) );
+    return window;
+}
+
+/*!
+*/
+
+Emulation::~Emulation()
+{
+  QListIterator<ScreenWindow*> windowIter(_windows);
+
+  while (windowIter.hasNext())
+  {
+    delete windowIter.next();
+  }
+
+  delete _screen[0];
+  delete _screen[1];
+  delete _decoder;
+}
+
+/*! change between primary and alternate _screen
+*/
+
+void Emulation::setScreen(int n)
+{
+  Screen *old = _currentScreen;
+  _currentScreen = _screen[n&1];
+  if (_currentScreen != old) 
+  {
+     old->setBusySelecting(false);
+
+     // tell all windows onto this emulation to switch to the newly active _screen
+     QListIterator<ScreenWindow*> windowIter(_windows);
+     while ( windowIter.hasNext() )
+     {
+         windowIter.next()->setScreen(_currentScreen);
+     }
+  }
+}
+
+void Emulation::clearHistory()
+{
+    _screen[0]->setScroll( _screen[0]->getScroll() , false );
+}
+void Emulation::setHistory(const HistoryType& t)
+{
+  _screen[0]->setScroll(t);
+
+  showBulk();
+}
+
+const HistoryType& Emulation::history()
+{
+  return _screen[0]->getScroll();
+}
+
+void Emulation::setCodec(const QTextCodec * qtc)
+{
+  Q_ASSERT( qtc );
+
+  _codec = qtc;
+  delete _decoder;
+  _decoder = _codec->makeDecoder();
+
+  emit useUtf8Request(utf8());
+}
+
+void Emulation::setCodec(EmulationCodec codec)
+{
+    if ( codec == Utf8Codec )
+        setCodec( QTextCodec::codecForName("utf8") );
+    else if ( codec == LocaleCodec )
+        setCodec( QTextCodec::codecForLocale() );
+}
+
+void Emulation::setKeyBindings(const QString& name)
+{
+  _keyTranslator = KeyboardTranslatorManager::instance()->findTranslator(name);
+}
+
+QString Emulation::keyBindings()
+{
+  return _keyTranslator->name();
+}
+
+
+// Interpreting Codes ---------------------------------------------------------
+
+/*
+   This section deals with decoding the incoming character stream.
+   Decoding means here, that the stream is first separated into `tokens'
+   which are then mapped to a `meaning' provided as operations by the
+   `Screen' class.
+*/
+
+/*!
+*/
+
+void Emulation::receiveChar(int c)
+// process application unicode input to terminal
+// this is a trivial scanner
+{
+  c &= 0xff;
+  switch (c)
+  {
+    case '\b'      : _currentScreen->BackSpace();                 break;
+    case '\t'      : _currentScreen->Tabulate();                  break;
+    case '\n'      : _currentScreen->NewLine();                   break;
+    case '\r'      : _currentScreen->Return();                    break;
+    case 0x07      : emit stateSet(NOTIFYBELL);
+                     break;
+    default        : _currentScreen->ShowCharacter(c);            break;
+  };
+}
+
+/* ------------------------------------------------------------------------- */
+/*                                                                           */
+/*                             Keyboard Handling                             */
+/*                                                                           */
+/* ------------------------------------------------------------------------- */
+
+/*!
+*/
+
+void Emulation::sendKeyEvent( QKeyEvent* ev )
+{
+  emit stateSet(NOTIFYNORMAL);
+  
+  if (!ev->text().isEmpty())
+  { // A block of text
+    // Note that the text is proper unicode.
+    // We should do a conversion here, but since this
+    // routine will never be used, we simply emit plain ascii.
+    //emit sendBlock(ev->text().toAscii(),ev->text().length());
+    emit sendData(ev->text().toUtf8(),ev->text().length());
+  }
+}
+
+void Emulation::sendString(const char*,int)
+{
+    // default implementation does nothing
+}
+
+void Emulation::sendMouseEvent(int /*buttons*/, int /*column*/, int /*row*/, int /*eventType*/)
+{
+    // default implementation does nothing
+}
+
+// Unblocking, Byte to Unicode translation --------------------------------- --
+
+/*
+   We are doing code conversion from locale to unicode first.
+TODO: Character composition from the old code.  See #96536
+*/
+
+void Emulation::receiveData(const char* text, int length)
+{
+	emit stateSet(NOTIFYACTIVITY);
+
+	bufferedUpdate();
+    	
+    QString unicodeText = _decoder->toUnicode(text,length);
+
+	//send characters to terminal emulator
+	for (int i=0;i<unicodeText.length();i++)
+	{
+		receiveChar(unicodeText[i].unicode());
+	}
+
+	//look for z-modem indicator
+	//-- someone who understands more about z-modems that I do may be able to move
+	//this check into the above for loop?
+	for (int i=0;i<length;i++)
+	{
+		if (text[i] == '\030')
+    		{
+      			if ((length-i-1 > 3) && (strncmp(text+i+1, "B00", 3) == 0))
+      				emit zmodemDetected();
+    		}
+	}
+}
+
+//OLDER VERSION
+//This version of onRcvBlock was commented out because
+//	a)  It decoded incoming characters one-by-one, which is slow in the current version of Qt (4.2 tech preview)
+//	b)  It messed up decoding of non-ASCII characters, with the result that (for example) chinese characters
+//	    were not printed properly.
+//
+//There is something about stopping the _decoder if "we get a control code halfway a multi-byte sequence" (see below)
+//which hasn't been ported into the newer function (above).  Hopefully someone who understands this better
+//can find an alternative way of handling the check.  
+
+
+/*void Emulation::onRcvBlock(const char *s, int len)
+{
+  emit notifySessionState(NOTIFYACTIVITY);
+  
+  bufferedUpdate();
+  for (int i = 0; i < len; i++)
+  {
+
+    QString result = _decoder->toUnicode(&s[i],1);
+    int reslen = result.length();
+
+    // If we get a control code halfway a multi-byte sequence
+    // we flush the _decoder and continue with the control code.
+    if ((s[i] < 32) && (s[i] > 0))
+    {
+       // Flush _decoder
+       while(!result.length())
+          result = _decoder->toUnicode(&s[i],1);
+       reslen = 1;
+       result.resize(reslen);
+       result[0] = QChar(s[i]);
+    }
+
+    for (int j = 0; j < reslen; j++)
+    {
+      if (result[j].characterategory() == QChar::Mark_NonSpacing)
+         _currentScreen->compose(result.mid(j,1));
+      else
+         onRcvChar(result[j].unicode());
+    }
+    if (s[i] == '\030')
+    {
+      if ((len-i-1 > 3) && (strncmp(s+i+1, "B00", 3) == 0))
+      	emit zmodemDetected();
+    }
+  }
+}*/
+
+// Selection --------------------------------------------------------------- --
+
+#if 0
+void Emulation::onSelectionBegin(const int x, const int y, const bool columnmode) {
+  if (!connected) return;
+  _currentScreen->setSelectionStart( x,y,columnmode);
+  showBulk();
+}
+
+void Emulation::onSelectionExtend(const int x, const int y) {
+  if (!connected) return;
+  _currentScreen->setSelectionEnd(x,y);
+  showBulk();
+}
+
+void Emulation::setSelection(const bool preserve_line_breaks) {
+  if (!connected) return;
+  QString t = _currentScreen->selectedText(preserve_line_breaks);
+  if (!t.isNull()) 
+  {
+    QListIterator< TerminalDisplay* > viewIter(_views);
+
+    while (viewIter.hasNext())    
+        viewIter.next()->setSelection(t);
+  }
+}
+
+void Emulation::testIsSelected(const int x, const int y, bool &selected)
+{
+  if (!connected) return;
+  selected=_currentScreen->isSelected(x,y);
+}
+
+void Emulation::clearSelection() {
+  if (!connected) return;
+  _currentScreen->clearSelection();
+  showBulk();
+}
+
+#endif 
+
+void Emulation::writeToStream( TerminalCharacterDecoder* _decoder , 
+                               int startLine ,
+                               int endLine) 
+{
+  _currentScreen->writeToStream(_decoder,startLine,endLine);
+}
+
+int Emulation::lineCount()
+{
+    // sum number of lines currently on _screen plus number of lines in history
+    return _currentScreen->getLines() + _currentScreen->getHistLines();
+}
+
+// Refreshing -------------------------------------------------------------- --
+
+#define BULK_TIMEOUT1 10
+#define BULK_TIMEOUT2 40
+
+/*!
+*/
+void Emulation::showBulk()
+{
+    _bulkTimer1.stop();
+    _bulkTimer2.stop();
+
+    emit outputChanged();
+
+    _currentScreen->resetScrolledLines();
+    _currentScreen->resetDroppedLines();
+}
+
+void Emulation::bufferedUpdate()
+{
+   _bulkTimer1.setSingleShot(true);
+   _bulkTimer1.start(BULK_TIMEOUT1);
+   if (!_bulkTimer2.isActive())
+   {
+      _bulkTimer2.setSingleShot(true);
+      _bulkTimer2.start(BULK_TIMEOUT2);
+   }
+}
+
+char Emulation::getErase() const
+{
+  return '\b';
+}
+
+void Emulation::setImageSize(int lines, int columns)
+{
+  //kDebug() << "Resizing image to: " << lines << "by" << columns << QTime::currentTime().msec();
+  Q_ASSERT( lines > 0 );
+  Q_ASSERT( columns > 0 );
+
+  _screen[0]->resizeImage(lines,columns);
+  _screen[1]->resizeImage(lines,columns);
+
+  emit imageSizeChanged(lines,columns);
+
+  bufferedUpdate();
+}
+
+QSize Emulation::imageSize()
+{
+  return QSize(_currentScreen->getColumns(), _currentScreen->getLines());
+}
+
+ushort ExtendedCharTable::extendedCharHash(ushort* unicodePoints , ushort length) const
+{
+    ushort hash = 0;
+    for ( ushort i = 0 ; i < length ; i++ )
+    {
+        hash = 31*hash + unicodePoints[i];
+    }
+    return hash;
+}
+bool ExtendedCharTable::extendedCharMatch(ushort hash , ushort* unicodePoints , ushort length) const
+{
+    ushort* entry = extendedCharTable[hash];
+
+    // compare given length with stored sequence length ( given as the first ushort in the 
+    // stored buffer ) 
+    if ( entry == 0 || entry[0] != length ) 
+       return false;
+    // if the lengths match, each character must be checked.  the stored buffer starts at
+    // entry[1]
+    for ( int i = 0 ; i < length ; i++ )
+    {
+        if ( entry[i+1] != unicodePoints[i] )
+           return false; 
+    } 
+    return true;
+}
+ushort ExtendedCharTable::createExtendedChar(ushort* unicodePoints , ushort length)
+{
+    // look for this sequence of points in the table
+    ushort hash = extendedCharHash(unicodePoints,length);
+
+    // check existing entry for match
+    while ( extendedCharTable.contains(hash) )
+    {
+        if ( extendedCharMatch(hash,unicodePoints,length) )
+        {
+            // this sequence already has an entry in the table, 
+            // return its hash
+            return hash;
+        }
+        else
+        {
+            // if hash is already used by another, different sequence of unicode character
+            // points then try next hash
+            hash++;
+        }
+    }    
+
+    
+     // add the new sequence to the table and
+     // return that index
+    ushort* buffer = new ushort[length+1];
+    buffer[0] = length;
+    for ( int i = 0 ; i < length ; i++ )
+       buffer[i+1] = unicodePoints[i]; 
+    
+    extendedCharTable.insert(hash,buffer);
+
+    return hash;
+}
+
+ushort* ExtendedCharTable::lookupExtendedChar(ushort hash , ushort& length) const
+{
+    // lookup index in table and if found, set the length
+    // argument and return a pointer to the character sequence
+
+    ushort* buffer = extendedCharTable[hash];
+    if ( buffer )
+    {
+        length = buffer[0];
+        return buffer+1;
+    }
+    else
+    {
+        length = 0;
+        return 0;
+    }
+}
+
+ExtendedCharTable::ExtendedCharTable()
+{
+}
+ExtendedCharTable::~ExtendedCharTable()
+{
+    // free all allocated character buffers
+    QHashIterator<ushort,ushort*> iter(extendedCharTable);
+    while ( iter.hasNext() )
+    {
+        iter.next();
+        delete[] iter.value();
+    }
+}
+
+// global instance
+ExtendedCharTable ExtendedCharTable::instance;
+
+
+//#include "moc_Emulation.cpp"
+
new file mode 100644
--- /dev/null
+++ b/gui//Emulation.h
@@ -0,0 +1,465 @@
+/*
+    This file is part of Konsole, an X terminal.
+    
+    Copyright (C) 2007 by Robert Knight <robertknight@gmail.com>
+    Copyright (C) 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
+
+    Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301  USA.
+*/
+
+#ifndef EMULATION_H
+#define EMULATION_H
+
+// System
+#include <stdio.h>
+
+// Qt 
+#include <QtGui/QKeyEvent>
+//#include <QPointer>
+#include <QtCore/QTextCodec>
+#include <QtCore/QTextStream>
+#include <QtCore/QTimer>
+
+
+namespace Konsole
+{
+
+class KeyboardTranslator;
+class HistoryType;
+class Screen;
+class ScreenWindow;
+class TerminalCharacterDecoder;
+
+/** 
+ * This enum describes the available states which 
+ * the terminal emulation may be set to.
+ *
+ * These are the values used by Emulation::stateChanged() 
+ */
+enum 
+{ 
+    /** The emulation is currently receiving user input. */
+    NOTIFYNORMAL=0, 
+    /** 
+     * The terminal program has triggered a bell event
+     * to get the user's attention.
+     */
+    NOTIFYBELL=1, 
+    /** 
+     * The emulation is currently receiving data from its 
+     * terminal input.
+     */
+    NOTIFYACTIVITY=2,
+
+    // unused here? 
+    NOTIFYSILENCE=3 
+};
+
+/**
+ * Base class for terminal emulation back-ends.
+ *
+ * The back-end is responsible for decoding an incoming character stream and 
+ * producing an output image of characters.
+ *
+ * When input from the terminal is received, the receiveData() slot should be called with
+ * the data which has arrived.  The emulation will process the data and update the 
+ * screen image accordingly.  The codec used to decode the incoming character stream
+ * into the unicode characters used internally can be specified using setCodec() 
+ *
+ * The size of the screen image can be specified by calling setImageSize() with the 
+ * desired number of lines and columns.  When new lines are added, old content
+ * is moved into a history store, which can be set by calling setHistory(). 
+ *
+ * The screen image can be accessed by creating a ScreenWindow onto this emulation 
+ * by calling createWindow().  Screen windows provide access to a section of the 
+ * output.  Each screen window covers the same number of lines and columns as the 
+ * image size returned by imageSize().  The screen window can be moved up and down
+ * and provides transparent access to both the current on-screen image and the 
+ * previous output.  The screen windows emit an outputChanged signal
+ * when the section of the image they are looking at changes.
+ * Graphical views can then render the contents of a screen window, listening for notifications
+ * of output changes from the screen window which they are associated with and updating 
+ * accordingly. 
+ *
+ * The emulation also is also responsible for converting input from the connected views such
+ * as keypresses and mouse activity into a character string which can be sent
+ * to the terminal program.  Key presses can be processed by calling the sendKeyEvent() slot,
+ * while mouse events can be processed using the sendMouseEvent() slot.  When the character
+ * stream has been produced, the emulation will emit a sendData() signal with a pointer
+ * to the character buffer.  This data should be fed to the standard input of the terminal
+ * process.  The translation of key presses into an output character stream is performed
+ * using a lookup in a set of key bindings which map key sequences to output
+ * character sequences.  The name of the key bindings set used can be specified using
+ * setKeyBindings()
+ *
+ * The emulation maintains certain state information which changes depending on the 
+ * input received.  The emulation can be reset back to its starting state by calling 
+ * reset().  
+ *
+ * The emulation also maintains an activity state, which specifies whether
+ * terminal is currently active ( when data is received ), normal
+ * ( when the terminal is idle or receiving user input ) or trying
+ * to alert the user ( also known as a "Bell" event ).  The stateSet() signal
+ * is emitted whenever the activity state is set.  This can be used to determine
+ * how long the emulation has been active/idle for and also respond to
+ * a 'bell' event in different ways.
+ */
+class Emulation : public QObject
+{ 
+Q_OBJECT
+
+public:
+ 
+   /** Constructs a new terminal emulation */ 
+   Emulation();
+  ~Emulation();
+
+  /**
+   * Creates a new window onto the output from this emulation.  The contents
+   * of the window are then rendered by views which are set to use this window using the
+   * TerminalDisplay::setScreenWindow() method.
+   */
+  ScreenWindow* createWindow();
+
+  /** Returns the size of the screen image which the emulation produces */
+  QSize imageSize();
+
+  /**
+   * Returns the total number of lines, including those stored in the history.
+   */ 
+  int lineCount();
+
+  
+  /** 
+   * Sets the history store used by this emulation.  When new lines
+   * are added to the output, older lines at the top of the screen are transferred to a history
+   * store.   
+   *
+   * The number of lines which are kept and the storage location depend on the 
+   * type of store.
+   */
+  void setHistory(const HistoryType&);
+  /** Returns the history store used by this emulation.  See setHistory() */
+  const HistoryType& history();
+  /** Clears the history scroll. */
+  void clearHistory();
+
+  /** 
+   * Copies the output history from @p startLine to @p endLine 
+   * into @p stream, using @p decoder to convert the terminal
+   * characters into text. 
+   *
+   * @param decoder A decoder which converts lines of terminal characters with 
+   * appearance attributes into output text.  PlainTextDecoder is the most commonly
+   * used decoder.
+   * @param startLine The first
+   */
+  virtual void writeToStream(TerminalCharacterDecoder* decoder,int startLine,int endLine);
+  
+  
+  /** Returns the codec used to decode incoming characters.  See setCodec() */
+  const QTextCodec* codec() { return _codec; }
+  /** Sets the codec used to decode incoming characters.  */
+  void setCodec(const QTextCodec*);
+
+  /** 
+   * Convenience method.  
+   * Returns true if the current codec used to decode incoming
+   * characters is UTF-8
+   */
+  bool utf8() { Q_ASSERT(_codec); return _codec->mibEnum() == 106; }
+  
+
+  /** TODO Document me */
+  virtual char getErase() const;
+
+  /** 
+   * Sets the key bindings used to key events
+   * ( received through sendKeyEvent() ) into character
+   * streams to send to the terminal.
+   */
+  void setKeyBindings(const QString& name);
+  /** 
+   * Returns the name of the emulation's current key bindings.
+   * See setKeyBindings()
+   */
+  QString keyBindings();
+
+  /** 
+   * Copies the current image into the history and clears the screen.
+   */
+  virtual void clearEntireScreen() =0;
+
+  /** Resets the state of the terminal. */
+  virtual void reset() =0;
+
+  /** 
+   * Returns true if the active terminal program wants
+   * mouse input events.
+   *
+   * The programUsesMouseChanged() signal is emitted when this
+   * changes.
+   */
+  bool programUsesMouse() const;
+
+public slots: 
+
+  /** Change the size of the emulation's image */
+  virtual void setImageSize(int lines, int columns);
+  
+  /** 
+   * Interprets a sequence of characters and sends the result to the terminal.
+   * This is equivalent to calling sendKeyEvent() for each character in @p text in succession.
+   */
+  virtual void sendText(const QString& text) = 0;
+
+  /** 
+   * Interprets a key press event and emits the sendData() signal with
+   * the resulting character stream. 
+   */
+  virtual void sendKeyEvent(QKeyEvent*);
+ 
+  /** 
+   * Converts information about a mouse event into an xterm-compatible escape
+   * sequence and emits the character sequence via sendData()
+   */
+  virtual void sendMouseEvent(int buttons, int column, int line, int eventType);
+  
+  /**
+   * Sends a string of characters to the foreground terminal process. 
+   *
+   * @param string The characters to send.  
+   * @param length Length of @p string or if set to a negative value, @p string will
+   * be treated as a null-terminated string and its length will be determined automatically.
+   */
+  virtual void sendString(const char* string, int length = -1) = 0;
+
+  /** 
+   * Processes an incoming stream of characters.  receiveData() decodes the incoming
+   * character buffer using the current codec(), and then calls receiveChar() for
+   * each unicode character in the resulting buffer.  
+   *
+   * receiveData() also starts a timer which causes the outputChanged() signal
+   * to be emitted when it expires.  The timer allows multiple updates in quick
+   * succession to be buffered into a single outputChanged() signal emission.
+   *
+   * @param buffer A string of characters received from the terminal program.
+   * @param len The length of @p buffer
+   */
+  void receiveData(const char* buffer,int len);
+
+signals:
+
+  /** 
+   * Emitted when a buffer of data is ready to send to the 
+   * standard input of the terminal.
+   *
+   * @param data The buffer of data ready to be sent
+   * @paran len The length of @p data in bytes
+   */
+  void sendData(const char* data,int len);
+
+  /** 
+   * Requests that sending of input to the emulation
+   * from the terminal process be suspended or resumed.
+   *
+   * @param suspend If true, requests that sending of 
+   * input from the terminal process' stdout be 
+   * suspended.  Otherwise requests that sending of
+   * input be resumed. 
+   */
+  void lockPtyRequest(bool suspend);
+
+  /**
+   * Requests that the pty used by the terminal process
+   * be set to UTF 8 mode.  
+   *
+   * TODO: More documentation
+   */
+  void useUtf8Request(bool);
+
+  /**
+   * Emitted when the activity state of the emulation is set.
+   *
+   * @param state The new activity state, one of NOTIFYNORMAL, NOTIFYACTIVITY
+   * or NOTIFYBELL
+   */
+  void stateSet(int state);
+
+  /** TODO Document me */
+  void zmodemDetected();
+
+
+  /**
+   * Requests that the color of the text used
+   * to represent the tabs associated with this
+   * emulation be changed.  This is a Konsole-specific
+   * extension from pre-KDE 4 times.
+   *
+   * TODO: Document how the parameter works.
+   */
+  void changeTabTextColorRequest(int color);
+
+  /** 
+   * This is emitted when the program running in the shell indicates whether or
+   * not it is interested in mouse events.
+   *
+   * @param usesMouse This will be true if the program wants to be informed about
+   * mouse events or false otherwise.
+   */
+  void programUsesMouseChanged(bool usesMouse);
+
+  /** 
+   * Emitted when the contents of the screen image change.
+   * The emulation buffers the updates from successive image changes,
+   * and only emits outputChanged() at sensible intervals when
+   * there is a lot of terminal activity.
+   *
+   * Normally there is no need for objects other than the screen windows
+   * created with createWindow() to listen for this signal.
+   *
+   * ScreenWindow objects created using createWindow() will emit their
+   * own outputChanged() signal in response to this signal. 
+   */
+  void outputChanged();
+
+  /**
+   * Emitted when the program running in the terminal wishes to update the 
+   * session's title.  This also allows terminal programs to customize other
+   * aspects of the terminal emulation display. 
+   *
+   * This signal is emitted when the escape sequence "\033]ARG;VALUE\007"
+   * is received in the input string, where ARG is a number specifying what
+   * should change and VALUE is a string specifying the new value.
+   *
+   * TODO:  The name of this method is not very accurate since this method
+   * is used to perform a whole range of tasks besides just setting
+   * the user-title of the session.    
+   *
+   * @param title Specifies what to change.
+   * <ul>
+   * <li>0 - Set window icon text and session title to @p newTitle</li>
+   * <li>1 - Set window icon text to @p newTitle</li>
+   * <li>2 - Set session title to @p newTitle</li>
+   * <li>11 - Set the session's default background color to @p newTitle,
+   *         where @p newTitle can be an HTML-style string (#RRGGBB) or a named
+   *         color (eg 'red', 'blue').  
+   *         See http://doc.trolltech.com/4.2/qcolor.html#setNamedColor for more
+   *         details.
+   * </li>
+   * <li>31 - Supposedly treats @p newTitle as a URL and opens it (NOT IMPLEMENTED)</li>
+   * <li>32 - Sets the icon associated with the session.  @p newTitle is the name 
+   *    of the icon to use, which can be the name of any icon in the current KDE icon
+   *    theme (eg: 'konsole', 'kate', 'folder_home')</li>
+   * </ul>
+   * @param newTitle Specifies the new title 
+   */
+
+  void titleChanged(int title,const QString& newTitle);
+
+  /**
+   * Emitted when the program running in the terminal changes the
+   * screen size.
+   */
+  void imageSizeChanged(int lineCount , int columnCount);
+
+  /** 
+   * Emitted when the terminal program requests to change various properties
+   * of the terminal display.  
+   *
+   * A profile change command occurs when a special escape sequence, followed
+   * by a string containing a series of name and value pairs is received.
+   * This string can be parsed using a ProfileCommandParser instance.
+   *
+   * @param text A string expected to contain a series of key and value pairs in
+   * the form:  name=value;name2=value2 ...
+   */
+  void profileChangeCommandReceived(const QString& text);
+
+protected:
+  virtual void setMode  (int mode) = 0;
+  virtual void resetMode(int mode) = 0;
+   
+ /** 
+   * Processes an incoming character.  See receiveData()
+   * @p ch A unicode character code. 
+   */
+  virtual void receiveChar(int ch);
+
+  /** 
+   * Sets the active screen.  The terminal has two screens, primary and alternate.
+   * The primary screen is used by default.  When certain interactive programs such
+   * as Vim are run, they trigger a switch to the alternate screen.
+   *
+   * @param index 0 to switch to the primary screen, or 1 to switch to the alternate screen
+   */
+  void setScreen(int index); 
+
+  enum EmulationCodec
+  {
+      LocaleCodec = 0,
+      Utf8Codec   = 1
+  };
+  void setCodec(EmulationCodec codec); // codec number, 0 = locale, 1=utf8
+
+
+  QList<ScreenWindow*> _windows;
+  
+  Screen* _currentScreen;  // pointer to the screen which is currently active, 
+                            // this is one of the elements in the screen[] array
+
+  Screen* _screen[2];      // 0 = primary screen ( used by most programs, including the shell
+                            //                      scrollbars are enabled in this mode )
+                            // 1 = alternate      ( used by vi , emacs etc.
+                            //                      scrollbars are not enabled in this mode )
+                            
+  
+  //decodes an incoming C-style character stream into a unicode QString using 
+  //the current text codec.  (this allows for rendering of non-ASCII characters in text files etc.)
+  const QTextCodec* _codec;
+  QTextDecoder* _decoder;
+
+  const KeyboardTranslator* _keyTranslator; // the keyboard layout
+
+protected slots:
+  /** 
+   * Schedules an update of attached views.
+   * Repeated calls to bufferedUpdate() in close succession will result in only a single update,
+   * much like the Qt buffered update of widgets. 
+   */
+  void bufferedUpdate();
+
+private slots: 
+
+  // triggered by timer, causes the emulation to send an updated screen image to each
+  // view
+  void showBulk(); 
+
+  void usesMouseChanged(bool usesMouse);
+
+private:
+
+  bool _usesMouse;
+  QTimer _bulkTimer1;
+  QTimer _bulkTimer2;
+  
+};
+
+}
+
+#endif // ifndef EMULATION_H
new file mode 100644
--- /dev/null
+++ b/gui//ExtendedDefaultTranslator.h
@@ -0,0 +1,74 @@
+"keyboard \"Default (XFree 4)\""
+"key Escape             : \"\\E\""
+"key Tab   -Shift       : \"\\t\"\n"
+"key Tab   +Shift+Ansi  : \"\\E[Z\"\n"
+"key Tab   +Shift-Ansi  : \"\\t\"\n"
+"key Backtab     +Ansi  : \"\\E[Z\"\n"
+"key Backtab     -Ansi  : \"\\t\"\n"
+"key Return-Shift-NewLine : \"\\r\"\n"
+"key Return-Shift+NewLine : \"\\r\\n\"\n"
+"key Return+Shift         : \"\\EOM\"\n"
+"key Backspace      : \"\\x7f\"\n"
+"key Up   -Shift-Ansi : \"\\EA\"\n"
+"key Down -Shift-Ansi : \"\\EB\"\n"
+"key Right-Shift-Ansi : \"\\EC\"\n"
+"key Left -Shift-Ansi : \"\\ED\"\n"
+"key Up    -Shift-AnyMod+Ansi+AppCuKeys           : \"\\EOA\"\n"
+"key Down  -Shift-AnyMod+Ansi+AppCuKeys           : \"\\EOB\"\n"
+"key Right -Shift-AnyMod+Ansi+AppCuKeys           : \"\\EOC\"\n"
+"key Left  -Shift-AnyMod+Ansi+AppCuKeys           : \"\\EOD\"\n"
+"key Up    -Shift-AnyMod+Ansi-AppCuKeys           : \"\\E[A\"\n"
+"key Down  -Shift-AnyMod+Ansi-AppCuKeys           : \"\\E[B\"\n"
+"key Right -Shift-AnyMod+Ansi-AppCuKeys           : \"\\E[C\"\n"
+"key Left  -Shift-AnyMod+Ansi-AppCuKeys           : \"\\E[D\"\n"
+"key Up    -Shift+AnyMod+Ansi                     : \"\\E[1;*A\"\n"
+"key Down  -Shift+AnyMod+Ansi                     : \"\\E[1;*B\"\n"
+"key Right -Shift+AnyMod+Ansi                     : \"\\E[1;*C\"\n"
+"key Left  -Shift+AnyMod+Ansi                     : \"\\E[1;*D\"\n"
+"key Enter+NewLine : \"\\r\\n\"\n"
+"key Enter-NewLine : \"\\r\"\n"
+"key Home        -AnyMod     -AppCuKeys           : \"\\E[H\"  \n"
+"key End         -AnyMod     -AppCuKeys           : \"\\E[F\"  \n"
+"key Home        -AnyMod     +AppCuKeys           : \"\\EOH\"  \n"
+"key End         -AnyMod     +AppCuKeys           : \"\\EOF\"  \n"
+"key Home        +AnyMod                          : \"\\E[1;*H\"\n"
+"key End         +AnyMod                          : \"\\E[1;*F\"\n"
+"key Insert      -AnyMod                          : \"\\E[2~\"\n"
+"key Delete      -AnyMod                          : \"\\E[3~\"\n"
+"key Insert      +AnyMod                          : \"\\E[2;*~\"\n"
+"key Delete      +AnyMod                          : \"\\E[3;*~\"\n"
+"key Prior -Shift-AnyMod                          : \"\\E[5~\"\n"
+"key Next  -Shift-AnyMod                          : \"\\E[6~\"\n"
+"key Prior -Shift+AnyMod                          : \"\\E[5;*~\"\n"
+"key Next  -Shift+AnyMod                          : \"\\E[6;*~\"\n"
+"key F1          -AnyMod                          : \"\\EOP\"\n"
+"key F2          -AnyMod                          : \"\\EOQ\"\n"
+"key F3          -AnyMod                          : \"\\EOR\"\n"
+"key F4          -AnyMod                          : \"\\EOS\"\n"
+"key F5          -AnyMod                          : \"\\E[15~\"\n"
+"key F6          -AnyMod                          : \"\\E[17~\"\n"
+"key F7          -AnyMod                          : \"\\E[18~\"\n"
+"key F8          -AnyMod                          : \"\\E[19~\"\n"
+"key F9          -AnyMod                          : \"\\E[20~\"\n"
+"key F10         -AnyMod                          : \"\\E[21~\"\n"
+"key F11         -AnyMod                          : \"\\E[23~\"\n"
+"key F12         -AnyMod                          : \"\\E[24~\"\n"
+"key F1          +AnyMod                          : \"\\EO*P\"\n"
+"key F2          +AnyMod                          : \"\\EO*Q\"\n"
+"key F3          +AnyMod                          : \"\\EO*R\"\n"
+"key F4          +AnyMod                          : \"\\EO*S\"\n"
+"key F5          +AnyMod                          : \"\\E[15;*~\"\n"
+"key F6          +AnyMod                          : \"\\E[17;*~\"\n"
+"key F7          +AnyMod                          : \"\\E[18;*~\"\n"
+"key F8          +AnyMod                          : \"\\E[19;*~\"\n"
+"key F9          +AnyMod                          : \"\\E[20;*~\"\n"
+"key F10         +AnyMod                          : \"\\E[21;*~\"\n"
+"key F11         +AnyMod                          : \"\\E[23;*~\"\n"
+"key F12         +AnyMod                          : \"\\E[24;*~\"\n"
+"key Space +Control : \"\\x00\"\n"
+"key Up    +Shift-AppScreen  : scrollLineUp\n"
+"key Prior +Shift-AppScreen  : scrollPageUp\n"
+"key Down  +Shift-AppScreen  : scrollLineDown\n"
+"key Next  +Shift-AppScreen  : scrollPageDown\n"
+"key ScrollLock     : scrollLock\n"
+"\0"
new file mode 100644
--- /dev/null
+++ b/gui//Filter.cpp
@@ -0,0 +1,562 @@
+/*
+    Copyright (C) 2007 by Robert Knight <robertknight@gmail.com>
+
+    Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301  USA.
+*/
+
+// Own
+#include "Filter.h"
+
+// System
+#include <iostream>
+
+// Qt
+#include <QtGui/QAction>
+#include <QtGui/QApplication>
+#include <QtGui/QClipboard>
+#include <QtCore/QString>
+
+#include <QtCore/QSharedData>
+#include <QtCore>
+
+// KDE
+//#include <KLocale>
+//#include <KRun>
+
+// Konsole
+#include "TerminalCharacterDecoder.h"
+
+using namespace Konsole;
+
+FilterChain::~FilterChain()
+{
+    QMutableListIterator<Filter*> iter(*this);
+    
+    while ( iter.hasNext() )
+    {
+        Filter* filter = iter.next();
+        iter.remove();
+        delete filter;
+    }
+}
+
+void FilterChain::addFilter(Filter* filter)
+{
+    append(filter);
+}
+void FilterChain::removeFilter(Filter* filter)
+{
+    removeAll(filter);
+}
+bool FilterChain::containsFilter(Filter* filter)
+{
+    return contains(filter);
+}
+void FilterChain::reset()
+{
+    QListIterator<Filter*> iter(*this);
+    while (iter.hasNext())
+        iter.next()->reset();
+}
+void FilterChain::setBuffer(const QString* buffer , const QList<int>* linePositions)
+{
+    QListIterator<Filter*> iter(*this);
+    while (iter.hasNext())
+        iter.next()->setBuffer(buffer,linePositions);
+}
+void FilterChain::process()
+{
+    QListIterator<Filter*> iter(*this);
+    while (iter.hasNext())
+        iter.next()->process();
+}
+void FilterChain::clear()
+{
+    QList<Filter*>::clear();
+}
+Filter::HotSpot* FilterChain::hotSpotAt(int line , int column) const
+{
+    QListIterator<Filter*> iter(*this);
+    while (iter.hasNext())
+    {
+        Filter* filter = iter.next();
+        Filter::HotSpot* spot = filter->hotSpotAt(line,column);
+        if ( spot != 0 )
+        {
+            return spot;
+        }
+    }
+
+    return 0;
+}
+
+QList<Filter::HotSpot*> FilterChain::hotSpots() const
+{
+    QList<Filter::HotSpot*> list;
+    QListIterator<Filter*> iter(*this);
+    while (iter.hasNext())
+    {
+        Filter* filter = iter.next();
+        list << filter->hotSpots();
+    }
+    return list;
+}
+//QList<Filter::HotSpot*> FilterChain::hotSpotsAtLine(int line) const;
+
+TerminalImageFilterChain::TerminalImageFilterChain()
+: _buffer(0)
+, _linePositions(0)
+{
+}
+
+TerminalImageFilterChain::~TerminalImageFilterChain()
+{
+    delete _buffer;
+    delete _linePositions;
+}
+
+void TerminalImageFilterChain::setImage(const Character* const image , int lines , int columns, const QVector<LineProperty>& lineProperties)
+{
+//qDebug("%s %d", __FILE__, __LINE__);
+    if (empty())
+        return;
+//qDebug("%s %d", __FILE__, __LINE__);
+
+    // reset all filters and hotspots
+    reset();
+//qDebug("%s %d", __FILE__, __LINE__);
+
+    PlainTextDecoder decoder;
+    decoder.setTrailingWhitespace(false);
+    
+//qDebug("%s %d", __FILE__, __LINE__);
+    // setup new shared buffers for the filters to process on
+    QString* newBuffer = new QString();
+    QList<int>* newLinePositions = new QList<int>();
+    setBuffer( newBuffer , newLinePositions );
+
+    // free the old buffers
+    delete _buffer;
+    delete _linePositions;
+
+    _buffer = newBuffer;
+    _linePositions = newLinePositions;
+
+    QTextStream lineStream(_buffer);
+    decoder.begin(&lineStream);
+
+    for (int i=0 ; i < lines ; i++)
+    {
+        _linePositions->append(_buffer->length());
+        decoder.decodeLine(image + i*columns,columns,LINE_DEFAULT);
+
+        // pretend that each line ends with a newline character.
+        // this prevents a link that occurs at the end of one line
+        // being treated as part of a link that occurs at the start of the next line
+        //
+        // the downside is that links which are spread over more than one line are not
+        // highlighted.  
+        //
+        // TODO - Use the "line wrapped" attribute associated with lines in a
+        // terminal image to avoid adding this imaginary character for wrapped
+        // lines
+        if ( !(lineProperties.value(i,LINE_DEFAULT) & LINE_WRAPPED) )
+        	lineStream << QChar('\n');
+    }
+    decoder.end();
+//    qDebug("%s %d", __FILE__, __LINE__);
+}
+
+Filter::Filter() :
+_linePositions(0),
+_buffer(0)
+{
+}
+
+Filter::~Filter()
+{
+    QListIterator<HotSpot*> iter(_hotspotList);
+    while (iter.hasNext())
+    {
+        delete iter.next();
+    }
+}
+void Filter::reset()
+{
+    _hotspots.clear();
+    _hotspotList.clear();
+}
+
+void Filter::setBuffer(const QString* buffer , const QList<int>* linePositions)
+{
+    _buffer = buffer;
+    _linePositions = linePositions;
+}
+
+void Filter::getLineColumn(int position , int& startLine , int& startColumn)
+{
+    Q_ASSERT( _linePositions );
+    Q_ASSERT( _buffer );
+
+
+    for (int i = 0 ; i < _linePositions->count() ; i++)
+    {
+        //kDebug() << "line position at " << i << " = " << _linePositions[i];
+        int nextLine = 0;
+
+        if ( i == _linePositions->count()-1 )
+        {
+            nextLine = _buffer->length() + 1;
+        }
+        else
+        {
+            nextLine = _linePositions->value(i+1);
+        }
+
+       // kDebug() << "pos - " << position << " line pos(" << i<< ") " << _linePositions->value(i) << 
+       //     " next = " << nextLine << " buffer len = " << _buffer->length();
+
+        if ( _linePositions->value(i) <= position && position < nextLine ) 
+        {
+            startLine = i;
+            startColumn = position - _linePositions->value(i);
+            return;
+        }
+    }
+}
+    
+
+/*void Filter::addLine(const QString& text)
+{
+    _linePositions << _buffer.length();
+    _buffer.append(text);
+}*/
+
+const QString* Filter::buffer()
+{
+    return _buffer;
+}
+Filter::HotSpot::~HotSpot()
+{
+}
+void Filter::addHotSpot(HotSpot* spot)
+{
+    _hotspotList << spot;
+
+    for (int line = spot->startLine() ; line <= spot->endLine() ; line++)
+    {
+        _hotspots.insert(line,spot);
+    }    
+}
+QList<Filter::HotSpot*> Filter::hotSpots() const
+{
+    return _hotspotList;
+}
+QList<Filter::HotSpot*> Filter::hotSpotsAtLine(int line) const
+{
+    return _hotspots.values(line);
+}
+
+Filter::HotSpot* Filter::hotSpotAt(int line , int column) const
+{
+    QListIterator<HotSpot*> spotIter(_hotspots.values(line));
+
+    while (spotIter.hasNext())
+    {
+        HotSpot* spot = spotIter.next();
+        
+        if ( spot->startLine() == line && spot->startColumn() > column )
+            continue;
+        if ( spot->endLine() == line && spot->endColumn() < column )
+            continue;
+       
+        return spot;
+    }
+
+    return 0;
+}
+
+Filter::HotSpot::HotSpot(int startLine , int startColumn , int endLine , int endColumn)
+    : _startLine(startLine)
+    , _startColumn(startColumn)
+    , _endLine(endLine)
+    , _endColumn(endColumn)
+    , _type(NotSpecified)
+{
+}
+QString Filter::HotSpot::tooltip() const
+{
+    return QString();
+}
+QList<QAction*> Filter::HotSpot::actions()
+{
+    return QList<QAction*>();
+}
+int Filter::HotSpot::startLine() const
+{
+    return _startLine;
+}
+int Filter::HotSpot::endLine() const
+{
+    return _endLine;
+}
+int Filter::HotSpot::startColumn() const
+{
+    return _startColumn;
+}
+int Filter::HotSpot::endColumn() const
+{
+    return _endColumn;
+}
+Filter::HotSpot::Type Filter::HotSpot::type() const
+{
+    return _type;
+}
+void Filter::HotSpot::setType(Type type)
+{
+    _type = type;
+}
+
+RegExpFilter::RegExpFilter()
+{
+}
+
+RegExpFilter::HotSpot::HotSpot(int startLine,int startColumn,int endLine,int endColumn)
+    : Filter::HotSpot(startLine,startColumn,endLine,endColumn)
+{
+    setType(Marker);
+}
+
+void RegExpFilter::HotSpot::activate(QObject*)
+{
+}
+
+void RegExpFilter::HotSpot::setCapturedTexts(const QStringList& texts)
+{
+    _capturedTexts = texts;
+}
+QStringList RegExpFilter::HotSpot::capturedTexts() const
+{
+    return _capturedTexts;
+}
+
+void RegExpFilter::setRegExp(const QRegExp& regExp) 
+{
+    _searchText = regExp;
+}
+QRegExp RegExpFilter::regExp() const
+{
+    return _searchText;
+}
+/*void RegExpFilter::reset(int)
+{
+    _buffer = QString();
+}*/
+void RegExpFilter::process()
+{
+    int pos = 0;
+    const QString* text = buffer();
+
+    Q_ASSERT( text );
+
+    // ignore any regular expressions which match an empty string.
+    // otherwise the while loop below will run indefinitely
+    static const QString emptyString("");
+    if ( _searchText.exactMatch(emptyString) )
+        return;
+
+    while(pos >= 0)
+    {
+        pos = _searchText.indexIn(*text,pos);
+
+        if ( pos >= 0 )
+        {
+
+            int startLine = 0;
+            int endLine = 0;
+            int startColumn = 0;
+            int endColumn = 0;
+
+            
+            //kDebug() << "pos from " << pos << " to " << pos + _searchText.matchedLength();
+            
+            getLineColumn(pos,startLine,startColumn);
+            getLineColumn(pos + _searchText.matchedLength(),endLine,endColumn);
+
+            //kDebug() << "start " << startLine << " / " << startColumn;
+            //kDebug() << "end " << endLine << " / " << endColumn;
+
+            RegExpFilter::HotSpot* spot = newHotSpot(startLine,startColumn,
+                                           endLine,endColumn);
+            spot->setCapturedTexts(_searchText.capturedTexts());
+
+            addHotSpot( spot );  
+            pos += _searchText.matchedLength();
+
+            // if matchedLength == 0, the program will get stuck in an infinite loop
+            Q_ASSERT( _searchText.matchedLength() > 0 );
+        }
+    }    
+}
+
+RegExpFilter::HotSpot* RegExpFilter::newHotSpot(int startLine,int startColumn,
+                                                int endLine,int endColumn)
+{
+    return new RegExpFilter::HotSpot(startLine,startColumn,
+                                                  endLine,endColumn);
+}
+RegExpFilter::HotSpot* UrlFilter::newHotSpot(int startLine,int startColumn,int endLine,
+                                                    int endColumn)
+{
+    return new UrlFilter::HotSpot(startLine,startColumn,
+                                               endLine,endColumn);
+}
+UrlFilter::HotSpot::HotSpot(int startLine,int startColumn,int endLine,int endColumn)
+: RegExpFilter::HotSpot(startLine,startColumn,endLine,endColumn)
+, _urlObject(new FilterObject(this))
+{
+    setType(Link);
+}
+QString UrlFilter::HotSpot::tooltip() const
+{
+    QString url = capturedTexts().first();
+
+    const UrlType kind = urlType();
+
+    if ( kind == StandardUrl )
+        return QString(); 
+    else if ( kind == Email )
+        return QString(); 
+    else
+        return QString();
+}
+UrlFilter::HotSpot::UrlType UrlFilter::HotSpot::urlType() const
+{
+    QString url = capturedTexts().first();
+    
+    if ( FullUrlRegExp.exactMatch(url) )
+        return StandardUrl;
+    else if ( EmailAddressRegExp.exactMatch(url) )
+        return Email;
+    else
+        return Unknown;
+}
+
+void UrlFilter::HotSpot::activate(QObject* object)
+{
+    QString url = capturedTexts().first();
+
+    const UrlType kind = urlType();
+
+    const QString& actionName = object ? object->objectName() : QString();
+
+    if ( actionName == "copy-action" )
+    {
+        //kDebug() << "Copying url to clipboard:" << url;
+
+        QApplication::clipboard()->setText(url);
+        return;
+    }
+
+    if ( !object || actionName == "open-action" )
+    {
+        if ( kind == StandardUrl )
+        {
+            // if the URL path does not include the protocol ( eg. "www.kde.org" ) then
+            // prepend http:// ( eg. "www.kde.org" --> "http://www.kde.org" )
+            if (!url.contains("://"))
+            {
+                url.prepend("http://");
+            }
+        } 
+        else if ( kind == Email )
+        {
+            url.prepend("mailto:");
+        }
+    
+//        new KRun(url,QApplication::activeWindow());
+    }
+}
+
+// Note:  Altering these regular expressions can have a major effect on the performance of the filters 
+// used for finding URLs in the text, especially if they are very general and could match very long
+// pieces of text.
+// Please be careful when altering them.
+
+//regexp matches:
+// full url:  
+// protocolname:// or www. followed by anything other than whitespaces, <, >, ' or ", and ends before whitespaces, <, >, ', ", ], !, comma and dot
+const QRegExp UrlFilter::FullUrlRegExp("(www\\.(?!\\.)|[a-z][a-z0-9+.-]*://)[^\\s<>'\"]+[^!,\\.\\s<>'\"\\]]");
+// email address:
+// [word chars, dots or dashes]@[word chars, dots or dashes].[word chars]
+const QRegExp UrlFilter::EmailAddressRegExp("\\b(\\w|\\.|-)+@(\\w|\\.|-)+\\.\\w+\\b");
+
+// matches full url or email address
+const QRegExp UrlFilter::CompleteUrlRegExp('('+FullUrlRegExp.pattern()+'|'+
+                                            EmailAddressRegExp.pattern()+')');
+
+UrlFilter::UrlFilter()
+{
+    setRegExp( CompleteUrlRegExp );
+}
+UrlFilter::HotSpot::~HotSpot()
+{
+    delete _urlObject;
+}
+void FilterObject::activated()
+{
+    _filter->activate(sender());
+}
+QList<QAction*> UrlFilter::HotSpot::actions()
+{
+    QList<QAction*> list;
+
+    const UrlType kind = urlType();
+
+    QAction* openAction = new QAction(_urlObject);
+    QAction* copyAction = new QAction(_urlObject);;
+
+    Q_ASSERT( kind == StandardUrl || kind == Email );
+
+    if ( kind == StandardUrl )
+    {
+        openAction->setText(("Open Link"));
+        copyAction->setText(("Copy Link Address"));
+    }
+    else if ( kind == Email )
+    {
+        openAction->setText(("Send Email To..."));
+        copyAction->setText(("Copy Email Address"));
+    }
+
+    // object names are set here so that the hotspot performs the
+    // correct action when activated() is called with the triggered
+    // action passed as a parameter.
+    openAction->setObjectName("open-action");
+    copyAction->setObjectName("copy-action");
+
+    QObject::connect( openAction , SIGNAL(triggered()) , _urlObject , SLOT(activated()) );
+    QObject::connect( copyAction , SIGNAL(triggered()) , _urlObject , SLOT(activated()) );
+
+    list << openAction;
+    list << copyAction;
+
+    return list; 
+}
+
+//#include "moc_Filter.cpp"
new file mode 100644
--- /dev/null
+++ b/gui//Filter.h
@@ -0,0 +1,383 @@
+/*
+    Copyright (C) 2007 by Robert Knight <robertknight@gmail.com>
+
+    Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301  USA.
+*/
+
+#ifndef FILTER_H
+#define FILTER_H
+
+// Qt
+#include <QtGui/QAction>
+#include <QtCore/QList>
+#include <QtCore/QObject>
+#include <QtCore/QStringList>
+#include <QtCore/QHash>
+#include <QtCore/QRegExp>
+
+// Local
+#include "Character.h"
+
+namespace Konsole
+{
+
+/**
+ * A filter processes blocks of text looking for certain patterns (such as URLs or keywords from a list)
+ * and marks the areas which match the filter's patterns as 'hotspots'.
+ *
+ * Each hotspot has a type identifier associated with it ( such as a link or a highlighted section ),
+ * and an action.  When the user performs some activity such as a mouse-click in a hotspot area ( the exact
+ * action will depend on what is displaying the block of text which the filter is processing ), the hotspot's
+ * activate() method should be called.  Depending on the type of hotspot this will trigger a suitable response.
+ *
+ * For example, if a hotspot represents a URL then a suitable action would be opening that URL in a web browser.
+ * Hotspots may have more than one action, in which case the list of actions can be obtained using the 
+ * actions() method.
+ *
+ * Different subclasses of filter will return different types of hotspot.
+ * Subclasses must reimplement the process() method to examine a block of text and identify sections of interest.
+ * When processing the text they should create instances of Filter::HotSpot subclasses for sections of interest
+ * and add them to the filter's list of hotspots using addHotSpot()
+ */
+class Filter
+{
+public:
+    /**
+    * Represents an area of text which matched the pattern a particular filter has been looking for.
+    *
+    * Each hotspot has a type identifier associated with it ( such as a link or a highlighted section ),
+    * and an action.  When the user performs some activity such as a mouse-click in a hotspot area ( the exact
+    * action will depend on what is displaying the block of text which the filter is processing ), the hotspot's
+    * activate() method should be called.  Depending on the type of hotspot this will trigger a suitable response.
+    *
+    * For example, if a hotspot represents a URL then a suitable action would be opening that URL in a web browser.
+    * Hotspots may have more than one action, in which case the list of actions can be obtained using the 
+    * actions() method.  These actions may then be displayed in a popup menu or toolbar for example. 
+    */
+    class HotSpot
+    {
+    public:
+       /** 
+        * Constructs a new hotspot which covers the area from (@p startLine,@p startColumn) to (@p endLine,@p endColumn)
+        * in a block of text.
+        */
+       HotSpot(int startLine , int startColumn , int endLine , int endColumn);
+       virtual ~HotSpot();
+
+       enum Type
+       {
+            // the type of the hotspot is not specified
+            NotSpecified,
+            // this hotspot represents a clickable link
+            Link,
+            // this hotspot represents a marker
+            Marker
+       }; 
+
+       /** Returns the line when the hotspot area starts */
+       int startLine() const;
+       /** Returns the line where the hotspot area ends */
+       int endLine() const;
+       /** Returns the column on startLine() where the hotspot area starts */
+       int startColumn() const;
+       /** Returns the column on endLine() where the hotspot area ends */
+       int endColumn() const;
+       /** 
+        * Returns the type of the hotspot.  This is usually used as a hint for views on how to represent
+        * the hotspot graphically.  eg.  Link hotspots are typically underlined when the user mouses over them
+        */
+       Type type() const;
+       /** 
+        * Causes the an action associated with a hotspot to be triggered. 
+        *
+        * @param object The object which caused the hotspot to be triggered.  This is
+        * typically null ( in which case the default action should be performed ) or
+        * one of the objects from the actions() list.  In which case the associated
+        * action should be performed. 
+        */
+       virtual void activate(QObject* object = 0) = 0; 
+       /** 
+        * Returns a list of actions associated with the hotspot which can be used in a 
+        * menu or toolbar 
+        */
+       virtual QList<QAction*> actions();
+
+       /** 
+        * Returns the text of a tooltip to be shown when the mouse moves over the hotspot, or
+        * an empty string if there is no tooltip associated with this hotspot.
+        *
+        * The default implementation returns an empty string. 
+        */
+       virtual QString tooltip() const;
+
+    protected:
+       /** Sets the type of a hotspot.  This should only be set once */
+       void setType(Type type);
+
+    private:
+       int    _startLine;
+       int    _startColumn;
+       int    _endLine;
+       int    _endColumn;
+       Type _type;
+    
+    };
+
+    /** Constructs a new filter. */
+    Filter();
+    virtual ~Filter();
+
+    /** Causes the filter to process the block of text currently in its internal buffer */
+    virtual void process() = 0;
+
+    /** 
+     * Empties the filters internal buffer and resets the line count back to 0.
+     * All hotspots are deleted. 
+     */
+    void reset();
+
+    /** Adds a new line of text to the filter and increments the line count */
+    //void addLine(const QString& string);
+
+    /** Returns the hotspot which covers the given @p line and @p column, or 0 if no hotspot covers that area */
+    HotSpot* hotSpotAt(int line , int column) const;
+
+    /** Returns the list of hotspots identified by the filter */
+    QList<HotSpot*> hotSpots() const;
+
+    /** Returns the list of hotspots identified by the filter which occur on a given line */
+    QList<HotSpot*> hotSpotsAtLine(int line) const;
+
+    /** 
+     * TODO: Document me
+     */
+    void setBuffer(const QString* buffer , const QList<int>* linePositions);
+
+protected:
+    /** Adds a new hotspot to the list */
+    void addHotSpot(HotSpot*);
+    /** Returns the internal buffer */
+    const QString* buffer();
+    /** Converts a character position within buffer() to a line and column */
+    void getLineColumn(int position , int& startLine , int& startColumn);
+
+private:
+    QMultiHash<int,HotSpot*> _hotspots;
+    QList<HotSpot*> _hotspotList;
+    
+    const QList<int>* _linePositions;
+    const QString* _buffer;
+};
+
+/** 
+ * A filter which searches for sections of text matching a regular expression and creates a new RegExpFilter::HotSpot 
+ * instance for them.
+ *
+ * Subclasses can reimplement newHotSpot() to return custom hotspot types when matches for the regular expression
+ * are found. 
+ */
+class RegExpFilter : public Filter
+{
+public:
+    /** 
+     * Type of hotspot created by RegExpFilter.  The capturedTexts() method can be used to find the text
+     * matched by the filter's regular expression.
+     */
+    class HotSpot : public Filter::HotSpot
+    {
+    public:
+        HotSpot(int startLine, int startColumn, int endLine , int endColumn);
+        virtual void activate(QObject* object = 0);
+
+        /** Sets the captured texts associated with this hotspot */
+        void setCapturedTexts(const QStringList& texts);
+        /** Returns the texts found by the filter when matching the filter's regular expression */
+        QStringList capturedTexts() const;
+    private:
+        QStringList _capturedTexts;
+    };
+
+    /** Constructs a new regular expression filter */
+    RegExpFilter();
+
+    /** 
+     * Sets the regular expression which the filter searches for in blocks of text. 
+     *
+     * Regular expressions which match the empty string are treated as not matching
+     * anything. 
+     */
+    void setRegExp(const QRegExp& text);
+    /** Returns the regular expression which the filter searches for in blocks of text */
+    QRegExp regExp() const;
+
+    /** 
+     * Reimplemented to search the filter's text buffer for text matching regExp() 
+     *
+     * If regexp matches the empty string, then process() will return immediately
+     * without finding results. 
+     */
+    virtual void process();
+
+protected:
+    /** 
+     * Called when a match for the regular expression is encountered.  Subclasses should reimplement this
+     * to return custom hotspot types
+     */
+    virtual RegExpFilter::HotSpot* newHotSpot(int startLine,int startColumn,
+                                    int endLine,int endColumn);
+
+private:
+    QRegExp _searchText;
+};
+
+class FilterObject;
+
+/** A filter which matches URLs in blocks of text */
+class UrlFilter : public RegExpFilter 
+{
+public:
+    /** 
+     * Hotspot type created by UrlFilter instances.  The activate() method opens a web browser 
+     * at the given URL when called.
+     */
+    class HotSpot : public RegExpFilter::HotSpot 
+    {
+    public:
+        HotSpot(int startLine,int startColumn,int endLine,int endColumn);
+        virtual ~HotSpot();
+
+        virtual QList<QAction*> actions();
+
+        /** 
+         * Open a web browser at the current URL.  The url itself can be determined using
+         * the capturedTexts() method.
+         */
+        virtual void activate(QObject* object = 0);
+
+        virtual QString tooltip() const;
+    private:
+        enum UrlType
+        {
+            StandardUrl,
+            Email,
+            Unknown
+        };
+        UrlType urlType() const;
+
+        FilterObject* _urlObject;
+    };
+
+    UrlFilter();
+
+protected:
+    virtual RegExpFilter::HotSpot* newHotSpot(int,int,int,int);
+
+private:
+    
+    static const QRegExp FullUrlRegExp;
+    static const QRegExp EmailAddressRegExp;
+
+    // combined OR of FullUrlRegExp and EmailAddressRegExp
+    static const QRegExp CompleteUrlRegExp; 
+};
+
+class FilterObject : public QObject
+{
+Q_OBJECT
+public:
+    FilterObject(Filter::HotSpot* filter) : _filter(filter) {}
+private slots:
+    void activated();
+private:
+    Filter::HotSpot* _filter;
+};
+
+/** 
+ * A chain which allows a group of filters to be processed as one. 
+ * The chain owns the filters added to it and deletes them when the chain itself is destroyed.
+ *
+ * Use addFilter() to add a new filter to the chain.  
+ * When new text to be filtered arrives, use addLine() to add each additional
+ * line of text which needs to be processed and then after adding the last line, use
+ * process() to cause each filter in the chain to process the text.
+ *
+ * After processing a block of text, the reset() method can be used to set the filter chain's
+ * internal cursor back to the first line.
+ *
+ * The hotSpotAt() method will return the first hotspot which covers a given position.
+ *
+ * The hotSpots() and hotSpotsAtLine() method return all of the hotspots in the text and on
+ * a given line respectively.
+ */
+class FilterChain : protected QList<Filter*>
+{
+public:
+    virtual ~FilterChain();
+
+    /** Adds a new filter to the chain.  The chain will delete this filter when it is destroyed */
+    void addFilter(Filter* filter);
+    /** Removes a filter from the chain.  The chain will no longer delete the filter when destroyed */
+    void removeFilter(Filter* filter);
+    /** Returns true if the chain contains @p filter */
+    bool containsFilter(Filter* filter);
+    /** Removes all filters from the chain */
+    void clear();
+
+    /** Resets each filter in the chain */
+    void reset();
+    /**
+     * Processes each filter in the chain 
+     */
+    void process();
+
+    /** Sets the buffer for each filter in the chain to process. */
+    void setBuffer(const QString* buffer , const QList<int>* linePositions); 
+
+    /** Returns the first hotspot which occurs at @p line, @p column or 0 if no hotspot was found */
+    Filter::HotSpot* hotSpotAt(int line , int column) const;
+    /** Returns a list of all the hotspots in all the chain's filters */
+    QList<Filter::HotSpot*> hotSpots() const;
+    /** Returns a list of all hotspots at the given line in all the chain's filters */
+    QList<Filter::HotSpot> hotSpotsAtLine(int line) const;
+
+};
+
+/** A filter chain which processes character images from terminal displays */
+class TerminalImageFilterChain : public FilterChain
+{
+public:
+    TerminalImageFilterChain();
+    virtual ~TerminalImageFilterChain();
+
+    /**
+     * Set the current terminal image to @p image.
+     *
+     * @param image The terminal image
+     * @param lines The number of lines in the terminal image
+     * @param columns The number of columns in the terminal image
+     */
+    void setImage(const Character* const image , int lines , int columns,
+				  const QVector<LineProperty>& lineProperties);  
+
+private:
+    QString* _buffer;
+    QList<int>* _linePositions;
+};
+
+}
+#endif //FILTER_H
new file mode 100644
--- /dev/null
+++ b/gui//History.cpp
@@ -0,0 +1,698 @@
+/*
+    This file is part of Konsole, an X terminal.
+    Copyright (C) 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
+
+    Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301  USA.
+*/
+
+// Own
+#include "History.h"
+
+// System
+#include <iostream>
+#include <stdlib.h>
+#include <assert.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <errno.h>
+
+
+// Reasonable line size
+#define LINE_SIZE	1024
+
+using namespace Konsole;
+
+/*
+   An arbitrary long scroll.
+
+   One can modify the scroll only by adding either cells
+   or newlines, but access it randomly.
+
+   The model is that of an arbitrary wide typewriter scroll
+   in that the scroll is a serie of lines and each line is
+   a serie of cells with no overwriting permitted.
+
+   The implementation provides arbitrary length and numbers
+   of cells and line/column indexed read access to the scroll
+   at constant costs.
+
+KDE4: Can we use QTemporaryFile here, instead of KTempFile?
+
+FIXME: some complain about the history buffer comsuming the
+       memory of their machines. This problem is critical
+       since the history does not behave gracefully in cases
+       where the memory is used up completely.
+
+       I put in a workaround that should handle it problem
+       now gracefully. I'm not satisfied with the solution.
+
+FIXME: Terminating the history is not properly indicated
+       in the menu. We should throw a signal.
+
+FIXME: There is noticeable decrease in speed, also. Perhaps,
+       there whole feature needs to be revisited therefore.
+       Disadvantage of a more elaborated, say block-oriented
+       scheme with wrap around would be it's complexity.
+*/
+
+//FIXME: tempory replacement for tmpfile
+//       this is here one for debugging purpose.
+
+//#define tmpfile xTmpFile
+
+// History File ///////////////////////////////////////////
+
+/*
+  A Row(X) data type which allows adding elements to the end.
+*/
+
+HistoryFile::HistoryFile()
+  : ion(-1),
+    length(0),
+	fileMap(0)
+{
+  if (tmpFile.open())
+  { 
+    tmpFile.setAutoRemove(true);
+    ion = tmpFile.handle();
+  }
+}
+
+HistoryFile::~HistoryFile()
+{
+	if (fileMap)
+		unmap();
+}
+
+//TODO:  Mapping the entire file in will cause problems if the history file becomes exceedingly large,
+//(ie. larger than available memory).  HistoryFile::map() should only map in sections of the file at a time,
+//to avoid this.
+void HistoryFile::map()
+{
+	assert( fileMap == 0 );
+
+	fileMap = (char*)mmap( 0 , length , PROT_READ , MAP_PRIVATE , ion , 0 );
+
+    //if mmap'ing fails, fall back to the read-lseek combination
+    if ( fileMap == MAP_FAILED )
+    {
+            readWriteBalance = 0; 
+            fileMap = 0;
+            qDebug() << ": mmap'ing history failed.  errno = " << errno;
+    }
+}
+
+void HistoryFile::unmap()
+{
+	int result = munmap( fileMap , length );
+	assert( result == 0 );
+
+	fileMap = 0;
+}
+
+bool HistoryFile::isMapped()
+{
+	return (fileMap != 0);
+}
+
+void HistoryFile::add(const unsigned char* bytes, int len)
+{
+  if ( fileMap )
+		  unmap();
+		
+  readWriteBalance++;
+
+  int rc = 0;
+
+  rc = lseek(ion,length,SEEK_SET); if (rc < 0) { perror("HistoryFile::add.seek"); return; }
+  rc = write(ion,bytes,len);       if (rc < 0) { perror("HistoryFile::add.write"); return; }
+  length += rc;
+}
+
+void HistoryFile::get(unsigned char* bytes, int len, int loc)
+{
+  //count number of get() calls vs. number of add() calls.  
+  //If there are many more get() calls compared with add() 
+  //calls (decided by using MAP_THRESHOLD) then mmap the log
+  //file to improve performance.
+  readWriteBalance--;
+  if ( !fileMap && readWriteBalance < MAP_THRESHOLD )
+		  map();
+
+  if ( fileMap )
+  {
+	for (int i=0;i<len;i++)
+			bytes[i]=fileMap[loc+i];
+  }
+  else
+  {	
+  	int rc = 0;
+
+  	if (loc < 0 || len < 0 || loc + len > length)
+    	fprintf(stderr,"getHist(...,%d,%d): invalid args.\n",len,loc);
+  	rc = lseek(ion,loc,SEEK_SET); if (rc < 0) { perror("HistoryFile::get.seek"); return; }
+  	rc = read(ion,bytes,len);     if (rc < 0) { perror("HistoryFile::get.read"); return; }
+  }
+}
+
+int HistoryFile::len()
+{
+  return length;
+}
+
+
+// History Scroll abstract base class //////////////////////////////////////
+
+
+HistoryScroll::HistoryScroll(HistoryType* t)
+  : m_histType(t)
+{
+}
+
+HistoryScroll::~HistoryScroll()
+{
+  delete m_histType;
+}
+
+bool HistoryScroll::hasScroll()
+{
+  return true;
+}
+
+// History Scroll File //////////////////////////////////////
+
+/* 
+   The history scroll makes a Row(Row(Cell)) from
+   two history buffers. The index buffer contains
+   start of line positions which refere to the cells
+   buffer.
+
+   Note that index[0] addresses the second line
+   (line #1), while the first line (line #0) starts
+   at 0 in cells.
+*/
+
+HistoryScrollFile::HistoryScrollFile(const QString &logFileName)
+  : HistoryScroll(new HistoryTypeFile(logFileName)),
+  m_logFileName(logFileName)
+{
+}
+
+HistoryScrollFile::~HistoryScrollFile()
+{
+}
+ 
+int HistoryScrollFile::getLines()
+{
+  return index.len() / sizeof(int);
+}
+
+int HistoryScrollFile::getLineLen(int lineno)
+{
+  return (startOfLine(lineno+1) - startOfLine(lineno)) / sizeof(Character);
+}
+
+bool HistoryScrollFile::isWrappedLine(int lineno)
+{
+  if (lineno>=0 && lineno <= getLines()) {
+    unsigned char flag;
+    lineflags.get((unsigned char*)&flag,sizeof(unsigned char),(lineno)*sizeof(unsigned char));
+    return flag;
+  }
+  return false;
+}
+
+int HistoryScrollFile::startOfLine(int lineno)
+{
+  if (lineno <= 0) return 0;
+  if (lineno <= getLines())
+    { 
+	
+	if (!index.isMapped())
+			index.map();
+	
+	int res;
+    index.get((unsigned char*)&res,sizeof(int),(lineno-1)*sizeof(int));
+    return res;
+    }
+  return cells.len();
+}
+
+void HistoryScrollFile::getCells(int lineno, int colno, int count, Character res[])
+{
+  cells.get((unsigned char*)res,count*sizeof(Character),startOfLine(lineno)+colno*sizeof(Character));
+}
+
+void HistoryScrollFile::addCells(const Character text[], int count)
+{
+  cells.add((unsigned char*)text,count*sizeof(Character));
+}
+
+void HistoryScrollFile::addLine(bool previousWrapped)
+{
+  if (index.isMapped())
+		  index.unmap();
+
+  int locn = cells.len();
+  index.add((unsigned char*)&locn,sizeof(int));
+  unsigned char flags = previousWrapped ? 0x01 : 0x00;
+  lineflags.add((unsigned char*)&flags,sizeof(unsigned char));
+}
+
+
+// History Scroll Buffer //////////////////////////////////////
+HistoryScrollBuffer::HistoryScrollBuffer(unsigned int maxLineCount)
+  : HistoryScroll(new HistoryTypeBuffer(maxLineCount))
+   ,_historyBuffer()
+   ,_maxLineCount(0)
+   ,_usedLines(0)
+   ,_head(0)
+{
+  setMaxNbLines(maxLineCount);
+}
+
+HistoryScrollBuffer::~HistoryScrollBuffer()
+{
+    delete[] _historyBuffer;
+}
+
+void HistoryScrollBuffer::addCellsVector(const QVector<Character>& cells)
+{
+    _head++;
+    if ( _usedLines < _maxLineCount )
+        _usedLines++;
+
+    if ( _head >= _maxLineCount )
+    {
+        _head = 0;
+    }
+
+    _historyBuffer[bufferIndex(_usedLines-1)] = cells;
+    _wrappedLine[bufferIndex(_usedLines-1)] = false;
+}
+void HistoryScrollBuffer::addCells(const Character a[], int count)
+{
+  HistoryLine newLine(count);
+  qCopy(a,a+count,newLine.begin());
+
+  addCellsVector(newLine);
+}
+
+void HistoryScrollBuffer::addLine(bool previousWrapped)
+{
+    _wrappedLine[bufferIndex(_usedLines-1)] = previousWrapped;
+}
+
+int HistoryScrollBuffer::getLines()
+{
+    return _usedLines;
+}
+
+int HistoryScrollBuffer::getLineLen(int lineNumber)
+{
+  Q_ASSERT( lineNumber >= 0 && lineNumber < _maxLineCount );
+
+  if ( lineNumber < _usedLines )
+  {
+    return _historyBuffer[bufferIndex(lineNumber)].size();
+  }
+  else
+  {
+    return 0;
+  }
+}
+
+bool HistoryScrollBuffer::isWrappedLine(int lineNumber)
+{
+  Q_ASSERT( lineNumber >= 0 && lineNumber < _maxLineCount );
+    
+  if (lineNumber < _usedLines)
+  {
+    //kDebug() << "Line" << lineNumber << "wrapped is" << _wrappedLine[bufferIndex(lineNumber)];
+    return _wrappedLine[bufferIndex(lineNumber)];
+  }
+  else
+    return false;
+}
+
+void HistoryScrollBuffer::getCells(int lineNumber, int startColumn, int count, Character* buffer)
+{
+  if ( count == 0 ) return;
+
+  Q_ASSERT( lineNumber < _maxLineCount );
+
+  if (lineNumber >= _usedLines) 
+  {
+    memset(buffer, 0, count * sizeof(Character));
+    return;
+  }
+  
+  const HistoryLine& line = _historyBuffer[bufferIndex(lineNumber)];
+
+  //kDebug() << "startCol " << startColumn;
+  //kDebug() << "line.size() " << line.size();
+  //kDebug() << "count " << count;
+
+  Q_ASSERT( startColumn <= line.size() - count );
+    
+  memcpy(buffer, line.constData() + startColumn , count * sizeof(Character));
+}
+
+void HistoryScrollBuffer::setMaxNbLines(unsigned int lineCount)
+{
+    HistoryLine* oldBuffer = _historyBuffer;
+    HistoryLine* newBuffer = new HistoryLine[lineCount];
+    
+    for ( int i = 0 ; i < qMin(_usedLines,(int)lineCount) ; i++ )
+    {
+        newBuffer[i] = oldBuffer[bufferIndex(i)];
+    }
+    
+    _usedLines = qMin(_usedLines,(int)lineCount);
+    _maxLineCount = lineCount;
+    _head = ( _usedLines == _maxLineCount ) ? 0 : _usedLines-1;
+
+    _historyBuffer = newBuffer;
+    delete[] oldBuffer;
+
+    _wrappedLine.resize(lineCount);
+}
+
+int HistoryScrollBuffer::bufferIndex(int lineNumber)
+{
+    Q_ASSERT( lineNumber >= 0 );
+    Q_ASSERT( lineNumber < _maxLineCount );
+    Q_ASSERT( (_usedLines == _maxLineCount) || lineNumber <= _head );
+
+    if ( _usedLines == _maxLineCount )
+    {
+        return (_head+lineNumber+1) % _maxLineCount;
+    }
+    else
+    {   
+        return lineNumber;
+    }
+}
+
+
+// History Scroll None //////////////////////////////////////
+
+HistoryScrollNone::HistoryScrollNone()
+  : HistoryScroll(new HistoryTypeNone())
+{
+}
+
+HistoryScrollNone::~HistoryScrollNone()
+{
+}
+
+bool HistoryScrollNone::hasScroll()
+{
+  return false;
+}
+
+int  HistoryScrollNone::getLines()
+{
+  return 0;
+}
+
+int  HistoryScrollNone::getLineLen(int)
+{
+  return 0;
+}
+
+bool HistoryScrollNone::isWrappedLine(int /*lineno*/)
+{
+  return false;
+}
+
+void HistoryScrollNone::getCells(int, int, int, Character [])
+{
+}
+
+void HistoryScrollNone::addCells(const Character [], int)
+{
+}
+
+void HistoryScrollNone::addLine(bool)
+{
+}
+
+// History Scroll BlockArray //////////////////////////////////////
+
+HistoryScrollBlockArray::HistoryScrollBlockArray(size_t size)
+  : HistoryScroll(new HistoryTypeBlockArray(size))
+{
+  m_blockArray.setHistorySize(size); // nb. of lines.
+}
+
+HistoryScrollBlockArray::~HistoryScrollBlockArray()
+{
+}
+
+int  HistoryScrollBlockArray::getLines()
+{
+  return m_lineLengths.count();
+}
+
+int  HistoryScrollBlockArray::getLineLen(int lineno)
+{
+    if ( m_lineLengths.contains(lineno) )
+        return m_lineLengths[lineno];
+    else
+        return 0;
+}
+
+bool HistoryScrollBlockArray::isWrappedLine(int /*lineno*/)
+{
+  return false;
+}
+
+void HistoryScrollBlockArray::getCells(int lineno, int colno,
+                                       int count, Character res[])
+{
+  if (!count) return;
+
+  const Block *b = m_blockArray.at(lineno);
+
+  if (!b) {
+    memset(res, 0, count * sizeof(Character)); // still better than random data
+    return;
+  }
+
+  assert(((colno + count) * sizeof(Character)) < ENTRIES);
+  memcpy(res, b->data + (colno * sizeof(Character)), count * sizeof(Character));
+}
+
+void HistoryScrollBlockArray::addCells(const Character a[], int count)
+{
+  Block *b = m_blockArray.lastBlock();
+  
+  if (!b) return;
+
+  // put cells in block's data
+  assert((count * sizeof(Character)) < ENTRIES);
+
+  memset(b->data, 0, ENTRIES);
+
+  memcpy(b->data, a, count * sizeof(Character));
+  b->size = count * sizeof(Character);
+
+  size_t res = m_blockArray.newBlock();
+  assert (res > 0);
+  Q_UNUSED( res );
+
+  m_lineLengths.insert(m_blockArray.getCurrent(), count);
+}
+
+void HistoryScrollBlockArray::addLine(bool)
+{
+}
+
+//////////////////////////////////////////////////////////////////////
+// History Types
+//////////////////////////////////////////////////////////////////////
+
+HistoryType::HistoryType()
+{
+}
+
+HistoryType::~HistoryType()
+{
+}
+
+//////////////////////////////
+
+HistoryTypeNone::HistoryTypeNone()
+{
+}
+
+bool HistoryTypeNone::isEnabled() const
+{
+  return false;
+}
+
+HistoryScroll* HistoryTypeNone::scroll(HistoryScroll *old) const
+{
+  delete old;
+  return new HistoryScrollNone();
+}
+
+int HistoryTypeNone::maximumLineCount() const
+{
+  return 0;
+}
+
+//////////////////////////////
+
+HistoryTypeBlockArray::HistoryTypeBlockArray(size_t size)
+  : m_size(size)
+{
+}
+
+bool HistoryTypeBlockArray::isEnabled() const
+{
+  return true;
+}
+
+int HistoryTypeBlockArray::maximumLineCount() const
+{
+  return m_size;
+}
+
+HistoryScroll* HistoryTypeBlockArray::scroll(HistoryScroll *old) const
+{
+  delete old;
+  return new HistoryScrollBlockArray(m_size);
+}
+
+
+//////////////////////////////
+
+HistoryTypeBuffer::HistoryTypeBuffer(unsigned int nbLines)
+  : m_nbLines(nbLines)
+{
+}
+
+bool HistoryTypeBuffer::isEnabled() const
+{
+  return true;
+}
+
+int HistoryTypeBuffer::maximumLineCount() const
+{
+  return m_nbLines;
+}
+
+HistoryScroll* HistoryTypeBuffer::scroll(HistoryScroll *old) const
+{
+  if (old)
+  {
+    HistoryScrollBuffer *oldBuffer = dynamic_cast<HistoryScrollBuffer*>(old);
+    if (oldBuffer)
+    {
+       oldBuffer->setMaxNbLines(m_nbLines);
+       return oldBuffer;
+    }
+
+    HistoryScroll *newScroll = new HistoryScrollBuffer(m_nbLines);
+    int lines = old->getLines();
+    int startLine = 0;
+    if (lines > (int) m_nbLines)
+       startLine = lines - m_nbLines;
+
+    Character line[LINE_SIZE];
+    for(int i = startLine; i < lines; i++)
+    {
+       int size = old->getLineLen(i);
+       if (size > LINE_SIZE)
+       {
+          Character *tmp_line = new Character[size];
+          old->getCells(i, 0, size, tmp_line);
+          newScroll->addCells(tmp_line, size);
+          newScroll->addLine(old->isWrappedLine(i));
+          delete [] tmp_line;
+       }
+       else
+       {
+          old->getCells(i, 0, size, line);
+          newScroll->addCells(line, size);
+          newScroll->addLine(old->isWrappedLine(i));
+       }
+    }
+    delete old;
+    return newScroll;
+  }
+  return new HistoryScrollBuffer(m_nbLines);
+}
+
+//////////////////////////////
+
+HistoryTypeFile::HistoryTypeFile(const QString& fileName)
+  : m_fileName(fileName)
+{
+}
+
+bool HistoryTypeFile::isEnabled() const
+{
+  return true;
+}
+
+const QString& HistoryTypeFile::getFileName() const
+{
+  return m_fileName;
+}
+
+HistoryScroll* HistoryTypeFile::scroll(HistoryScroll *old) const
+{
+  if (dynamic_cast<HistoryFile *>(old)) 
+     return old; // Unchanged.
+
+  HistoryScroll *newScroll = new HistoryScrollFile(m_fileName);
+
+  Character line[LINE_SIZE];
+  int lines = (old != 0) ? old->getLines() : 0;
+  for(int i = 0; i < lines; i++)
+  {
+     int size = old->getLineLen(i);
+     if (size > LINE_SIZE)
+     {
+        Character *tmp_line = new Character[size];
+        old->getCells(i, 0, size, tmp_line);
+        newScroll->addCells(tmp_line, size);
+        newScroll->addLine(old->isWrappedLine(i));
+        delete [] tmp_line;
+     }
+     else
+     {
+        old->getCells(i, 0, size, line);
+        newScroll->addCells(line, size);
+        newScroll->addLine(old->isWrappedLine(i));
+     }
+  }
+
+  delete old;
+  return newScroll; 
+}
+
+int HistoryTypeFile::maximumLineCount() const
+{
+  return 0;
+}
new file mode 100644
--- /dev/null
+++ b/gui//History.h
@@ -0,0 +1,344 @@
+/*
+    This file is part of Konsole, an X terminal.
+    Copyright (C) 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
+
+    Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301  USA.
+*/
+
+#ifndef TEHISTORY_H
+#define TEHISTORY_H
+
+// Qt
+#include <QtCore/QBitRef>
+#include <QtCore/QHash>
+#include <QtCore>
+
+// Konsole
+#include "BlockArray.h"
+#include "Character.h"
+
+namespace Konsole
+{
+
+#if 1
+/*
+   An extendable tmpfile(1) based buffer.
+*/
+
+class HistoryFile
+{
+public:
+  HistoryFile();
+  virtual ~HistoryFile();
+
+  virtual void add(const unsigned char* bytes, int len);
+  virtual void get(unsigned char* bytes, int len, int loc);
+  virtual int  len();
+
+  //mmaps the file in read-only mode
+  void map();
+  //un-mmaps the file
+  void unmap();
+  //returns true if the file is mmap'ed
+  bool isMapped();
+
+
+private:
+  int  ion;
+  int  length;
+  QTemporaryFile tmpFile;
+
+  //pointer to start of mmap'ed file data, or 0 if the file is not mmap'ed
+  char* fileMap;
+ 
+  //incremented whenver 'add' is called and decremented whenever
+  //'get' is called.
+  //this is used to detect when a large number of lines are being read and processed from the history
+  //and automatically mmap the file for better performance (saves the overhead of many lseek-read calls).
+  int readWriteBalance;
+
+  //when readWriteBalance goes below this threshold, the file will be mmap'ed automatically
+  static const int MAP_THRESHOLD = -1000;
+};
+#endif
+
+//////////////////////////////////////////////////////////////////////
+
+//////////////////////////////////////////////////////////////////////
+// Abstract base class for file and buffer versions
+//////////////////////////////////////////////////////////////////////
+class HistoryType;
+
+class HistoryScroll
+{
+public:
+  HistoryScroll(HistoryType*);
+ virtual ~HistoryScroll();
+
+  virtual bool hasScroll();
+
+  // access to history
+  virtual int  getLines() = 0;
+  virtual int  getLineLen(int lineno) = 0;
+  virtual void getCells(int lineno, int colno, int count, Character res[]) = 0;
+  virtual bool isWrappedLine(int lineno) = 0;
+
+  // backward compatibility (obsolete)
+  Character   getCell(int lineno, int colno) { Character res; getCells(lineno,colno,1,&res); return res; }
+
+  // adding lines.
+  virtual void addCells(const Character a[], int count) = 0;
+  // convenience method - this is virtual so that subclasses can take advantage
+  // of QVector's implicit copying
+  virtual void addCellsVector(const QVector<Character>& cells)
+  {
+    addCells(cells.data(),cells.size());
+  }
+
+  virtual void addLine(bool previousWrapped=false) = 0;
+
+  //
+  // FIXME:  Passing around constant references to HistoryType instances
+  // is very unsafe, because those references will no longer
+  // be valid if the history scroll is deleted.
+  //
+  const HistoryType& getType() { return *m_histType; }
+
+protected:
+  HistoryType* m_histType;
+
+};
+
+#if 1
+
+//////////////////////////////////////////////////////////////////////
+// File-based history (e.g. file log, no limitation in length)
+//////////////////////////////////////////////////////////////////////
+
+class HistoryScrollFile : public HistoryScroll
+{
+public:
+  HistoryScrollFile(const QString &logFileName);
+  virtual ~HistoryScrollFile();
+
+  virtual int  getLines();
+  virtual int  getLineLen(int lineno);
+  virtual void getCells(int lineno, int colno, int count, Character res[]);
+  virtual bool isWrappedLine(int lineno);
+
+  virtual void addCells(const Character a[], int count);
+  virtual void addLine(bool previousWrapped=false);
+
+private:
+  int startOfLine(int lineno);
+
+  QString m_logFileName;
+  HistoryFile index; // lines Row(int)
+  HistoryFile cells; // text  Row(Character)
+  HistoryFile lineflags; // flags Row(unsigned char)
+};
+
+
+//////////////////////////////////////////////////////////////////////
+// Buffer-based history (limited to a fixed nb of lines)
+//////////////////////////////////////////////////////////////////////
+class HistoryScrollBuffer : public HistoryScroll
+{
+public:
+  typedef QVector<Character> HistoryLine;
+
+  HistoryScrollBuffer(unsigned int maxNbLines = 1000);
+  virtual ~HistoryScrollBuffer();
+
+  virtual int  getLines();
+  virtual int  getLineLen(int lineno);
+  virtual void getCells(int lineno, int colno, int count, Character res[]);
+  virtual bool isWrappedLine(int lineno);
+
+  virtual void addCells(const Character a[], int count);
+  virtual void addCellsVector(const QVector<Character>& cells);
+  virtual void addLine(bool previousWrapped=false);
+
+  void setMaxNbLines(unsigned int nbLines);
+  unsigned int maxNbLines() { return _maxLineCount; }
+  
+
+private:
+  int bufferIndex(int lineNumber);
+
+  HistoryLine* _historyBuffer;
+  QBitArray _wrappedLine;
+  int _maxLineCount;
+  int _usedLines;  
+  int _head;
+  
+  //QVector<histline*> m_histBuffer;
+  //QBitArray m_wrappedLine;
+  //unsigned int m_maxNbLines;
+  //unsigned int m_nbLines;
+  //unsigned int m_arrayIndex;
+  //bool         m_buffFilled;
+};
+
+/*class HistoryScrollBufferV2 : public HistoryScroll
+{
+public:
+  virtual int  getLines();
+  virtual int  getLineLen(int lineno);
+  virtual void getCells(int lineno, int colno, int count, Character res[]);
+  virtual bool isWrappedLine(int lineno);
+
+  virtual void addCells(const Character a[], int count);
+  virtual void addCells(const QVector<Character>& cells);
+  virtual void addLine(bool previousWrapped=false);
+
+};*/
+
+#endif
+
+//////////////////////////////////////////////////////////////////////
+// Nothing-based history (no history :-)
+//////////////////////////////////////////////////////////////////////
+class HistoryScrollNone : public HistoryScroll
+{
+public:
+  HistoryScrollNone();
+  virtual ~HistoryScrollNone();
+
+  virtual bool hasScroll();
+
+  virtual int  getLines();
+  virtual int  getLineLen(int lineno);
+  virtual void getCells(int lineno, int colno, int count, Character res[]);
+  virtual bool isWrappedLine(int lineno);
+
+  virtual void addCells(const Character a[], int count);
+  virtual void addLine(bool previousWrapped=false);
+};
+
+//////////////////////////////////////////////////////////////////////
+// BlockArray-based history
+//////////////////////////////////////////////////////////////////////
+class HistoryScrollBlockArray : public HistoryScroll
+{
+public:
+  HistoryScrollBlockArray(size_t size);
+  virtual ~HistoryScrollBlockArray();
+
+  virtual int  getLines();
+  virtual int  getLineLen(int lineno);
+  virtual void getCells(int lineno, int colno, int count, Character res[]);
+  virtual bool isWrappedLine(int lineno);
+
+  virtual void addCells(const Character a[], int count);
+  virtual void addLine(bool previousWrapped=false);
+
+protected:
+  BlockArray m_blockArray;
+  QHash<int,size_t> m_lineLengths;
+};
+
+//////////////////////////////////////////////////////////////////////
+// History type
+//////////////////////////////////////////////////////////////////////
+
+class HistoryType
+{
+public:
+  HistoryType();
+  virtual ~HistoryType();
+
+  /**
+   * Returns true if the history is enabled ( can store lines of output )
+   * or false otherwise. 
+   */
+  virtual bool isEnabled()           const = 0;
+  /**
+   * Returns true if the history size is unlimited.
+   */
+  bool isUnlimited() const { return maximumLineCount() == 0; }
+  /**
+   * Returns the maximum number of lines which this history type
+   * can store or 0 if the history can store an unlimited number of lines.
+   */
+  virtual int maximumLineCount()    const = 0;
+
+  virtual HistoryScroll* scroll(HistoryScroll *) const = 0;
+};
+
+class HistoryTypeNone : public HistoryType
+{
+public:
+  HistoryTypeNone();
+
+  virtual bool isEnabled() const;
+  virtual int maximumLineCount() const;
+
+  virtual HistoryScroll* scroll(HistoryScroll *) const;
+};
+
+class HistoryTypeBlockArray : public HistoryType
+{
+public:
+  HistoryTypeBlockArray(size_t size);
+  
+  virtual bool isEnabled() const;
+  virtual int maximumLineCount() const;
+
+  virtual HistoryScroll* scroll(HistoryScroll *) const;
+
+protected:
+  size_t m_size;
+};
+
+#if 1 
+class HistoryTypeFile : public HistoryType
+{
+public:
+  HistoryTypeFile(const QString& fileName=QString());
+
+  virtual bool isEnabled() const;
+  virtual const QString& getFileName() const;
+  virtual int maximumLineCount() const;
+
+  virtual HistoryScroll* scroll(HistoryScroll *) const;
+
+protected:
+  QString m_fileName;
+};
+
+
+class HistoryTypeBuffer : public HistoryType
+{
+public:
+  HistoryTypeBuffer(unsigned int nbLines);
+  
+  virtual bool isEnabled() const;
+  virtual int maximumLineCount() const;
+
+  virtual HistoryScroll* scroll(HistoryScroll *) const;
+
+protected:
+  unsigned int m_nbLines;
+};
+
+#endif
+
+}
+
+#endif // TEHISTORY_H
new file mode 100644
--- /dev/null
+++ b/gui//KeyboardTranslator.cpp
@@ -0,0 +1,903 @@
+/*
+    This source file was part of Konsole, a terminal emulator.
+
+    Copyright (C) 2007 by Robert Knight <robertknight@gmail.com>
+
+    Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301  USA.
+*/
+
+// Own
+#include "KeyboardTranslator.h"
+
+// System
+#include <ctype.h>
+#include <stdio.h>
+
+// Qt
+#include <QtCore/QBuffer>
+//#include <KDebug>
+#include <QtCore/QFile>
+#include <QtCore/QFileInfo>
+#include <QtCore>
+#include <QtGui>
+
+// KDE
+//#include <KDebug>
+//#include <KLocale>
+//#include <KStandardDirs>
+
+using namespace Konsole;
+
+//this is for default REALLY fallback translator.
+
+//const char* KeyboardTranslatorManager::defaultTranslatorText =
+//#include "DefaultTranslatorText.h"
+//;
+
+//and this is default now translator - default.keytab from original Konsole
+const char* KeyboardTranslatorManager::defaultTranslatorText = 
+#include "ExtendedDefaultTranslator.h"
+;
+
+KeyboardTranslatorManager::KeyboardTranslatorManager()
+    : _haveLoadedAll(false)
+{
+}
+KeyboardTranslatorManager::~KeyboardTranslatorManager()
+{
+    qDeleteAll(_translators.values());
+}
+QString KeyboardTranslatorManager::findTranslatorPath(const QString& name)
+{
+    return QString("kb-layouts/" + name + ".keytab");
+}
+void KeyboardTranslatorManager::findTranslators()
+{
+    QDir dir("kb-layouts/");
+    QStringList filters;
+    filters << "*.keytab";
+    dir.setNameFilters(filters);
+    QStringList list = dir.entryList(filters); //(".keytab"); // = KGlobal::dirs()->findAllResources("data",
+                        //                                 "konsole/*.keytab",
+                        //                                 KStandardDirs::NoDuplicates);
+    list = dir.entryList(filters);
+    // add the name of each translator to the list and associated
+    // the name with a null pointer to indicate that the translator
+    // has not yet been loaded from disk
+    QStringListIterator listIter(list);
+    while (listIter.hasNext())
+    {
+        QString translatorPath = listIter.next();
+
+        QString name = QFileInfo(translatorPath).baseName();
+       
+        if ( !_translators.contains(name) ) {
+            _translators.insert(name,0);
+	}
+    }
+    _haveLoadedAll = true;
+}
+
+const KeyboardTranslator* KeyboardTranslatorManager::findTranslator(const QString& name)
+{
+    if ( name.isEmpty() )
+        return defaultTranslator();
+
+//here was smth wrong in original Konsole source 
+    findTranslators();
+
+    if ( _translators.contains(name) && _translators[name] != 0 ) {
+        return _translators[name];
+    }
+
+    KeyboardTranslator* translator = loadTranslator(name);
+
+    if ( translator != 0 )
+        _translators[name] = translator;
+    else if ( !name.isEmpty() )
+        qWarning() << "Unable to load translator" << name;
+
+    return translator;
+}
+
+bool KeyboardTranslatorManager::saveTranslator(const KeyboardTranslator* translator)
+{
+    const QString path = ".keytab";// = KGlobal::dirs()->saveLocation("data","konsole/")+translator->name()
+//           +".keytab";
+
+    qDebug() << "Saving translator to" << path;
+
+    QFile destination(path);
+    
+    if (!destination.open(QIODevice::WriteOnly | QIODevice::Text))
+    {
+        qWarning() << "Unable to save keyboard translation:" 
+                   << destination.errorString();
+
+        return false;
+    }
+
+    {
+        KeyboardTranslatorWriter writer(&destination);
+        writer.writeHeader(translator->description());
+    
+        QListIterator<KeyboardTranslator::Entry> iter(translator->entries());
+        while ( iter.hasNext() )
+            writer.writeEntry(iter.next());
+    }
+
+    destination.close();
+
+    return true;
+}
+
+KeyboardTranslator* KeyboardTranslatorManager::loadTranslator(const QString& name)
+{
+    const QString& path = findTranslatorPath(name);
+
+    QFile source(path); 
+    
+    if (name.isEmpty() || !source.open(QIODevice::ReadOnly | QIODevice::Text))
+        return 0;
+
+    return loadTranslator(&source,name);
+}
+
+const KeyboardTranslator* KeyboardTranslatorManager::defaultTranslator()
+{
+    qDebug() << "Loading default translator from text";
+    QBuffer textBuffer;
+    textBuffer.setData(defaultTranslatorText,strlen(defaultTranslatorText));
+
+    if (!textBuffer.open(QIODevice::ReadOnly))
+        return 0;
+
+    return loadTranslator(&textBuffer,"fallback");
+}
+
+KeyboardTranslator* KeyboardTranslatorManager::loadTranslator(QIODevice* source,const QString& name)
+{
+    KeyboardTranslator* translator = new KeyboardTranslator(name);
+    KeyboardTranslatorReader reader(source);
+    translator->setDescription( reader.description() );
+    
+    while ( reader.hasNextEntry() ) {
+        translator->addEntry(reader.nextEntry());
+    }	
+
+    source->close();
+
+    if ( !reader.parseError() )
+    {
+        return translator;
+    }
+    else
+    {
+        delete translator;
+        return 0;
+    }
+}
+
+KeyboardTranslatorWriter::KeyboardTranslatorWriter(QIODevice* destination)
+: _destination(destination)
+{
+    Q_ASSERT( destination && destination->isWritable() );
+
+    _writer = new QTextStream(_destination);
+}
+KeyboardTranslatorWriter::~KeyboardTranslatorWriter()
+{
+    delete _writer;
+}
+void KeyboardTranslatorWriter::writeHeader( const QString& description )
+{
+    *_writer << "keyboard \"" << description << '\"' << '\n';
+}
+void KeyboardTranslatorWriter::writeEntry( const KeyboardTranslator::Entry& entry )
+{
+    QString result;
+
+    if ( entry.command() != KeyboardTranslator::NoCommand )
+        result = entry.resultToString();
+    else
+        result = '\"' + entry.resultToString() + '\"';
+
+    *_writer << "key " << entry.conditionToString() << " : " << result << '\n';
+}
+
+
+// each line of the keyboard translation file is one of:
+//
+// - keyboard "name"
+// - key KeySequence : "characters"
+// - key KeySequence : CommandName
+//
+// KeySequence begins with the name of the key ( taken from the Qt::Key enum )
+// and is followed by the keyboard modifiers and state flags ( with + or - in front
+// of each modifier or flag to indicate whether it is required ).  All keyboard modifiers
+// and flags are optional, if a particular modifier or state is not specified it is 
+// assumed not to be a part of the sequence.  The key sequence may contain whitespace
+//
+// eg:  "key Up+Shift : scrollLineUp"
+//      "key Next-Shift : "\E[6~"
+//
+// (lines containing only whitespace are ignored, parseLine assumes that comments have
+// already been removed)
+//
+
+KeyboardTranslatorReader::KeyboardTranslatorReader( QIODevice* source )
+    : _source(source)
+    , _hasNext(false)
+{
+   // read input until we find the description
+   while ( _description.isEmpty() && !source->atEnd() )
+   {
+        const QList<Token>& tokens = tokenize( QString(source->readLine()) );
+   
+        if ( !tokens.isEmpty() && tokens.first().type == Token::TitleKeyword )
+        {
+            _description = (tokens[1].text.toUtf8());
+        }
+   }
+
+   readNext();
+}
+void KeyboardTranslatorReader::readNext() 
+{
+    // find next entry
+    while ( !_source->atEnd() )
+    {
+        const QList<Token>& tokens = tokenize( QString(_source->readLine()) );
+        if ( !tokens.isEmpty() && tokens.first().type == Token::KeyKeyword )
+        {
+            KeyboardTranslator::States flags = KeyboardTranslator::NoState;
+            KeyboardTranslator::States flagMask = KeyboardTranslator::NoState;
+            Qt::KeyboardModifiers modifiers = Qt::NoModifier;
+            Qt::KeyboardModifiers modifierMask = Qt::NoModifier;
+
+            int keyCode = Qt::Key_unknown;
+
+            decodeSequence(tokens[1].text.toLower(),
+                           keyCode,
+                           modifiers,
+                           modifierMask,
+                           flags,
+                           flagMask); 
+
+            KeyboardTranslator::Command command = KeyboardTranslator::NoCommand;
+            QByteArray text;
+
+            // get text or command
+            if ( tokens[2].type == Token::OutputText )
+            {
+                text = tokens[2].text.toLocal8Bit();
+            }
+            else if ( tokens[2].type == Token::Command )
+            {
+                // identify command
+				if (!parseAsCommand(tokens[2].text,command))
+					qWarning() << "Command" << tokens[2].text << "not understood.";
+            }
+
+            KeyboardTranslator::Entry newEntry;
+            newEntry.setKeyCode( keyCode );
+            newEntry.setState( flags );
+            newEntry.setStateMask( flagMask );
+            newEntry.setModifiers( modifiers );
+            newEntry.setModifierMask( modifierMask );
+            newEntry.setText( text );
+            newEntry.setCommand( command );
+
+            _nextEntry = newEntry;
+
+            _hasNext = true;
+
+            return;
+        }
+    } 
+
+    _hasNext = false;
+}
+
+bool KeyboardTranslatorReader::parseAsCommand(const QString& text,KeyboardTranslator::Command& command) 
+{
+	if ( text.compare("erase",Qt::CaseInsensitive) == 0 )
+		command = KeyboardTranslator::EraseCommand;
+    else if ( text.compare("scrollpageup",Qt::CaseInsensitive) == 0 )
+        command = KeyboardTranslator::ScrollPageUpCommand;
+    else if ( text.compare("scrollpagedown",Qt::CaseInsensitive) == 0 )
+        command = KeyboardTranslator::ScrollPageDownCommand;
+    else if ( text.compare("scrolllineup",Qt::CaseInsensitive) == 0 )
+        command = KeyboardTranslator::ScrollLineUpCommand;
+    else if ( text.compare("scrolllinedown",Qt::CaseInsensitive) == 0 )
+        command = KeyboardTranslator::ScrollLineDownCommand;
+    else if ( text.compare("scrolllock",Qt::CaseInsensitive) == 0 )
+        command = KeyboardTranslator::ScrollLockCommand;
+    else
+    	return false;
+
+	return true;
+}
+
+bool KeyboardTranslatorReader::decodeSequence(const QString& text,
+                                              int& keyCode,
+                                              Qt::KeyboardModifiers& modifiers,
+                                              Qt::KeyboardModifiers& modifierMask,
+                                              KeyboardTranslator::States& flags,
+                                              KeyboardTranslator::States& flagMask)
+{
+    bool isWanted = true; 
+    bool endOfItem = false;
+    QString buffer;
+
+    Qt::KeyboardModifiers tempModifiers = modifiers;
+    Qt::KeyboardModifiers tempModifierMask = modifierMask;
+    KeyboardTranslator::States tempFlags = flags;
+    KeyboardTranslator::States tempFlagMask = flagMask;
+
+    for ( int i = 0 ; i < text.count() ; i++ )
+    {
+        const QChar& ch = text[i];
+        bool isLastLetter = ( i == text.count()-1 );
+
+        endOfItem = true;
+        if ( ch.isLetterOrNumber() )
+        {
+            endOfItem = false;
+            buffer.append(ch);
+        }
+
+        if ( (endOfItem || isLastLetter) && !buffer.isEmpty() )
+        {
+            Qt::KeyboardModifier itemModifier = Qt::NoModifier;
+            int itemKeyCode = 0;
+            KeyboardTranslator::State itemFlag = KeyboardTranslator::NoState;
+
+            if ( parseAsModifier(buffer,itemModifier) )
+            {
+                tempModifierMask |= itemModifier;
+
+                if ( isWanted )
+                    tempModifiers |= itemModifier;
+            }
+            else if ( parseAsStateFlag(buffer,itemFlag) )
+            {
+                tempFlagMask |= itemFlag;
+
+                if ( isWanted )
+                    tempFlags |= itemFlag;
+            }
+            else if ( parseAsKeyCode(buffer,itemKeyCode) )
+                keyCode = itemKeyCode;
+            else
+                qDebug() << "Unable to parse key binding item:" << buffer;
+
+            buffer.clear();
+        }
+
+        // check if this is a wanted / not-wanted flag and update the 
+        // state ready for the next item
+        if ( ch == '+' )
+           isWanted = true;
+        else if ( ch == '-' )
+           isWanted = false; 
+    } 
+
+    modifiers = tempModifiers;
+    modifierMask = tempModifierMask;
+    flags = tempFlags;
+    flagMask = tempFlagMask;
+
+    return true;
+}
+
+bool KeyboardTranslatorReader::parseAsModifier(const QString& item , Qt::KeyboardModifier& modifier)
+{
+    if ( item == "shift" )
+        modifier = Qt::ShiftModifier;
+    else if ( item == "ctrl" || item == "control" )
+        modifier = Qt::ControlModifier;
+    else if ( item == "alt" )
+        modifier = Qt::AltModifier;
+    else if ( item == "meta" )
+        modifier = Qt::MetaModifier;
+	else if ( item == "keypad" )
+		modifier = Qt::KeypadModifier;
+    else
+        return false;
+
+    return true;
+}
+bool KeyboardTranslatorReader::parseAsStateFlag(const QString& item , KeyboardTranslator::State& flag)
+{
+    if ( item == "appcukeys" )
+        flag = KeyboardTranslator::CursorKeysState;
+    else if ( item == "ansi" )
+        flag = KeyboardTranslator::AnsiState;
+    else if ( item == "newline" )
+        flag = KeyboardTranslator::NewLineState;
+    else if ( item == "appscreen" )
+        flag = KeyboardTranslator::AlternateScreenState;
+    else if ( item == "anymod" )
+        flag = KeyboardTranslator::AnyModifierState;
+    else
+        return false;
+
+    return true;
+}
+bool KeyboardTranslatorReader::parseAsKeyCode(const QString& item , int& keyCode)
+{
+    QKeySequence sequence = QKeySequence::fromString(item);
+    if ( !sequence.isEmpty() )
+    {
+        keyCode = sequence[0];
+
+        if ( sequence.count() > 1 )
+        {
+            qDebug() << "Unhandled key codes in sequence: " << item;
+        }
+    }
+    // additional cases implemented for backwards compatibility with KDE 3
+    else if ( item == "prior" )
+        keyCode = Qt::Key_PageUp;
+    else if ( item == "next" )
+        keyCode = Qt::Key_PageDown;
+    else
+        return false;
+
+    return true;
+}
+
+QString KeyboardTranslatorReader::description() const
+{
+    return _description;
+}
+bool KeyboardTranslatorReader::hasNextEntry()
+{
+    return _hasNext;
+}
+KeyboardTranslator::Entry KeyboardTranslatorReader::createEntry( const QString& condition , 
+                                                                 const QString& result )
+{
+    QString entryString("keyboard \"temporary\"\nkey ");
+    entryString.append(condition);
+    entryString.append(" : ");
+
+	// if 'result' is the name of a command then the entry result will be that command,
+	// otherwise the result will be treated as a string to echo when the key sequence
+	// specified by 'condition' is pressed
+	KeyboardTranslator::Command command;
+	if (parseAsCommand(result,command))
+    	entryString.append(result);
+	else
+		entryString.append('\"' + result + '\"');
+
+    QByteArray array = entryString.toUtf8();
+
+    KeyboardTranslator::Entry entry;
+
+    QBuffer buffer(&array);
+    buffer.open(QIODevice::ReadOnly);
+    KeyboardTranslatorReader reader(&buffer);
+
+    if ( reader.hasNextEntry() )
+        entry = reader.nextEntry();
+
+    return entry;
+}
+
+KeyboardTranslator::Entry KeyboardTranslatorReader::nextEntry() 
+{
+    Q_ASSERT( _hasNext );
+
+
+    KeyboardTranslator::Entry entry = _nextEntry;
+
+    readNext();
+
+    return entry;
+}
+bool KeyboardTranslatorReader::parseError()
+{
+    return false;
+}
+QList<KeyboardTranslatorReader::Token> KeyboardTranslatorReader::tokenize(const QString& line)
+{
+    QString text = line.simplified();
+
+    // comment line: # comment
+    static QRegExp comment("\\#.*");
+    // title line: keyboard "title"
+    static QRegExp title("keyboard\\s+\"(.*)\"");
+    // key line: key KeySequence : "output"
+    // key line: key KeySequence : command
+    static QRegExp key("key\\s+([\\w\\+\\s\\-]+)\\s*:\\s*(\"(.*)\"|\\w+)");
+
+    QList<Token> list;
+
+    if ( text.isEmpty() || comment.exactMatch(text) )
+    {
+        return list;
+    }
+
+    if ( title.exactMatch(text) )
+    {
+        Token titleToken = { Token::TitleKeyword , QString() };
+        Token textToken = { Token::TitleText , title.capturedTexts()[1] };
+    
+        list << titleToken << textToken;
+    }
+    else if  ( key.exactMatch(text) )
+    {
+        Token keyToken = { Token::KeyKeyword , QString() };
+        Token sequenceToken = { Token::KeySequence , key.capturedTexts()[1].remove(' ') };
+
+        list << keyToken << sequenceToken;
+
+        if ( key.capturedTexts()[3].isEmpty() )
+        {
+            // capturedTexts()[2] is a command
+            Token commandToken = { Token::Command , key.capturedTexts()[2] };
+            list << commandToken;    
+        }   
+        else
+        {
+            // capturedTexts()[3] is the output string
+           Token outputToken = { Token::OutputText , key.capturedTexts()[3] };
+           list << outputToken;
+        }     
+    }
+    else
+    {
+        qWarning() << "Line in keyboard translator file could not be understood:" << text;
+    }
+
+    return list;
+}
+
+QList<QString> KeyboardTranslatorManager::allTranslators() 
+{
+    if ( !_haveLoadedAll )
+    {
+        findTranslators();
+    }
+
+    return _translators.keys();
+}
+
+KeyboardTranslator::Entry::Entry()
+: _keyCode(0)
+, _modifiers(Qt::NoModifier)
+, _modifierMask(Qt::NoModifier)
+, _state(NoState)
+, _stateMask(NoState)
+, _command(NoCommand)
+{
+}
+
+bool KeyboardTranslator::Entry::operator==(const Entry& rhs) const
+{
+    return _keyCode == rhs._keyCode &&
+           _modifiers == rhs._modifiers &&
+           _modifierMask == rhs._modifierMask &&
+           _state == rhs._state &&
+           _stateMask == rhs._stateMask &&
+           _command == rhs._command &&
+           _text == rhs._text;
+}
+
+bool KeyboardTranslator::Entry::matches(int keyCode , 
+                                        Qt::KeyboardModifiers modifiers,
+                                        States state) const
+{
+    if ( _keyCode != keyCode )
+        return false;
+
+    if ( (modifiers & _modifierMask) != (_modifiers & _modifierMask) ) 
+        return false;
+
+    // if modifiers is non-zero, the 'any modifier' state is implicit
+    if ( modifiers != 0 )
+        state |= AnyModifierState;
+
+    if ( (state & _stateMask) != (_state & _stateMask) )
+        return false;
+
+    // special handling for the 'Any Modifier' state, which checks for the presence of 
+    // any or no modifiers.  In this context, the 'keypad' modifier does not count.
+    bool anyModifiersSet = modifiers != 0 && modifiers != Qt::KeypadModifier;
+    if ( _stateMask & KeyboardTranslator::AnyModifierState )
+    {
+        // test fails if any modifier is required but none are set
+        if ( (_state & KeyboardTranslator::AnyModifierState) && !anyModifiersSet )
+           return false;
+
+        // test fails if no modifier is allowed but one or more are set
+        if ( !(_state & KeyboardTranslator::AnyModifierState) && anyModifiersSet )
+            return false;
+    }
+
+    return true;
+}
+QByteArray KeyboardTranslator::Entry::escapedText(bool expandWildCards,Qt::KeyboardModifiers modifiers) const
+{
+    QByteArray result(text(expandWildCards,modifiers));
+
+    for ( int i = 0 ; i < result.count() ; i++ )
+    {
+        char ch = result[i];
+        char replacement = 0;
+
+        switch ( ch )
+        {
+            case 27 : replacement = 'E'; break;
+            case 8  : replacement = 'b'; break;
+            case 12 : replacement = 'f'; break;
+            case 9  : replacement = 't'; break;
+            case 13 : replacement = 'r'; break;
+            case 10 : replacement = 'n'; break;
+            default:
+                // any character which is not printable is replaced by an equivalent
+                // \xhh escape sequence (where 'hh' are the corresponding hex digits)
+                if ( !QChar(ch).isPrint() )
+                    replacement = 'x';
+        }
+
+        if ( replacement == 'x' )
+        {
+            result.replace(i,1,"\\x"+QByteArray(1,ch).toInt(0, 16)); 
+        } else if ( replacement != 0 )
+        {
+            result.remove(i,1);
+            result.insert(i,'\\');
+            result.insert(i+1,replacement);
+        }
+    }
+
+    return result;
+}
+QByteArray KeyboardTranslator::Entry::unescape(const QByteArray& input) const
+{
+    QByteArray result(input);
+
+    for ( int i = 0 ; i < result.count()-1 ; i++ )
+    {
+
+        QByteRef ch = result[i];
+        if ( ch == '\\' )
+        {
+           char replacement[2] = {0,0};
+           int charsToRemove = 2;
+		   bool escapedChar = true;
+
+           switch ( result[i+1] )
+           {
+              case 'E' : replacement[0] = 27; break;
+              case 'b' : replacement[0] = 8 ; break;
+              case 'f' : replacement[0] = 12; break;
+              case 't' : replacement[0] = 9 ; break;
+              case 'r' : replacement[0] = 13; break;
+              case 'n' : replacement[0] = 10; break;
+              case 'x' :
+			  {
+                    // format is \xh or \xhh where 'h' is a hexadecimal
+                    // digit from 0-9 or A-F which should be replaced
+                    // with the corresponding character value
+                    char hexDigits[3] = {0};
+
+                    if ( (i < result.count()-2) && isxdigit(result[i+2]) )
+                            hexDigits[0] = result[i+2];
+                    if ( (i < result.count()-3) && isxdigit(result[i+3]) )
+                            hexDigits[1] = result[i+3];
+
+                    int charValue = 0;
+                    sscanf(hexDigits,"%x",&charValue);
+                    
+                    replacement[0] = (char)charValue; 
+
+                    charsToRemove = 2 + strlen(hexDigits);
+			  }
+              break;
+			  default:
+			  		escapedChar = false;
+           }
+
+           if ( escapedChar )
+               result.replace(i,charsToRemove,replacement);
+        }
+    }
+    
+    return result;
+}
+
+void KeyboardTranslator::Entry::insertModifier( QString& item , int modifier ) const
+{
+    if ( !(modifier & _modifierMask) )
+        return;
+
+    if ( modifier & _modifiers )
+        item += '+';
+    else
+        item += '-';
+
+    if ( modifier == Qt::ShiftModifier )
+        item += "Shift";
+    else if ( modifier == Qt::ControlModifier )
+        item += "Ctrl";
+    else if ( modifier == Qt::AltModifier )
+        item += "Alt";
+    else if ( modifier == Qt::MetaModifier )
+        item += "Meta";
+	else if ( modifier == Qt::KeypadModifier )
+		item += "KeyPad";
+}
+void KeyboardTranslator::Entry::insertState( QString& item , int state ) const
+{
+    if ( !(state & _stateMask) )
+        return;
+
+    if ( state & _state )
+        item += '+' ;
+    else
+        item += '-' ;
+
+    if ( state == KeyboardTranslator::AlternateScreenState )
+        item += "AppScreen";
+    else if ( state == KeyboardTranslator::NewLineState )
+        item += "NewLine";
+    else if ( state == KeyboardTranslator::AnsiState )
+        item += "Ansi";
+    else if ( state == KeyboardTranslator::CursorKeysState )
+        item += "AppCuKeys";
+    else if ( state == KeyboardTranslator::AnyModifierState )
+        item += "AnyMod";
+}
+QString KeyboardTranslator::Entry::resultToString(bool expandWildCards,Qt::KeyboardModifiers modifiers) const
+{
+    if ( !_text.isEmpty() )
+        return escapedText(expandWildCards,modifiers);
+	else if ( _command == EraseCommand )
+		return "Erase";
+    else if ( _command == ScrollPageUpCommand )
+        return "ScrollPageUp";
+    else if ( _command == ScrollPageDownCommand )
+        return "ScrollPageDown";
+    else if ( _command == ScrollLineUpCommand )
+        return "ScrollLineUp";
+    else if ( _command == ScrollLineDownCommand )
+        return "ScrollLineDown";
+    else if ( _command == ScrollLockCommand )
+        return "ScrollLock";
+
+    return QString();
+}
+QString KeyboardTranslator::Entry::conditionToString() const
+{
+    QString result = QKeySequence(_keyCode).toString();
+
+    // add modifiers
+    insertModifier( result , Qt::ShiftModifier );
+    insertModifier( result , Qt::ControlModifier );
+    insertModifier( result , Qt::AltModifier );
+    insertModifier( result , Qt::MetaModifier ); 
+
+    // add states
+    insertState( result , KeyboardTranslator::AlternateScreenState );
+    insertState( result , KeyboardTranslator::NewLineState );
+    insertState( result , KeyboardTranslator::AnsiState );
+    insertState( result , KeyboardTranslator::CursorKeysState );
+    insertState( result , KeyboardTranslator::AnyModifierState );
+
+    return result;
+}
+
+KeyboardTranslator::KeyboardTranslator(const QString& name)
+: _name(name)
+{
+}
+
+void KeyboardTranslator::setDescription(const QString& description) 
+{
+    _description = description;
+}
+QString KeyboardTranslator::description() const
+{
+    return _description;
+}
+void KeyboardTranslator::setName(const QString& name)
+{
+    _name = name;
+}
+QString KeyboardTranslator::name() const
+{
+    return _name;
+}
+
+QList<KeyboardTranslator::Entry> KeyboardTranslator::entries() const
+{
+    return _entries.values();
+}
+
+void KeyboardTranslator::addEntry(const Entry& entry)
+{
+    const int keyCode = entry.keyCode();
+    _entries.insertMulti(keyCode,entry);
+}
+void KeyboardTranslator::replaceEntry(const Entry& existing , const Entry& replacement)
+{
+    if ( !existing.isNull() )
+        _entries.remove(existing.keyCode());
+    _entries.insertMulti(replacement.keyCode(),replacement);
+}
+void KeyboardTranslator::removeEntry(const Entry& entry)
+{
+    _entries.remove(entry.keyCode());
+}
+KeyboardTranslator::Entry KeyboardTranslator::findEntry(int keyCode, Qt::KeyboardModifiers modifiers, States state) const
+{
+    if ( _entries.contains(keyCode) )
+    {
+        QList<Entry> entriesForKey = _entries.values(keyCode);
+        
+        QListIterator<Entry> iter(entriesForKey);
+
+        while (iter.hasNext())
+        {
+            const Entry& next = iter.next();
+            if ( next.matches(keyCode,modifiers,state) )
+                return next;
+        }
+
+        return Entry(); // entry not found
+    }
+    else
+    {
+        return Entry();
+    }
+    
+}
+void KeyboardTranslatorManager::addTranslator(KeyboardTranslator* translator)
+{
+    _translators.insert(translator->name(),translator);
+
+    if ( !saveTranslator(translator) )
+        qWarning() << "Unable to save translator" << translator->name()
+                   << "to disk.";
+}
+bool KeyboardTranslatorManager::deleteTranslator(const QString& name)
+{
+    Q_ASSERT( _translators.contains(name) );
+
+    // locate and delete
+    QString path = findTranslatorPath(name);
+    if ( QFile::remove(path) )
+    {
+        _translators.remove(name);
+        return true; 
+    }
+    else
+    {
+        qWarning() << "Failed to remove translator - " << path;
+        return false;
+    }
+}
+K_GLOBAL_STATIC( KeyboardTranslatorManager , theKeyboardTranslatorManager )
+KeyboardTranslatorManager* KeyboardTranslatorManager::instance()
+{
+    return theKeyboardTranslatorManager;
+}
new file mode 100644
--- /dev/null
+++ b/gui//KeyboardTranslator.h
@@ -0,0 +1,657 @@
+/*
+    This source file is part of Konsole, a terminal emulator.
+
+    Copyright (C) 2007 by Robert Knight <robertknight@gmail.com>
+
+    Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301  USA.
+*/
+
+#ifndef KEYBOARDTRANSLATOR_H
+#define KEYBOARDTRANSLATOR_H
+
+// Qt
+#include <QtCore/QHash>
+#include <QtCore/QList>
+#include <QtGui/QKeySequence>
+#include <QtCore/QMetaType>
+#include <QtCore/QVarLengthArray>
+#include <QtCore>
+
+typedef void (*CleanUpFunction)();
+
+/**
+ * @internal
+ *
+ * Helper class for K_GLOBAL_STATIC to clean up the object on library unload or application
+ * shutdown.
+ */
+class CleanUpGlobalStatic
+{
+    public:
+        CleanUpFunction func;
+
+        inline ~CleanUpGlobalStatic() { func(); }
+};
+
+
+//these directives are taken from the heart of kdecore
+
+# define K_GLOBAL_STATIC_STRUCT_NAME(NAME)
+
+#if QT_VERSION < 0x040400
+# define Q_BASIC_ATOMIC_INITIALIZER     Q_ATOMIC_INIT
+# define testAndSetOrdered              testAndSet
+#endif
+
+#define K_GLOBAL_STATIC(TYPE, NAME) K_GLOBAL_STATIC_WITH_ARGS(TYPE, NAME, ())
+
+#define K_GLOBAL_STATIC_WITH_ARGS(TYPE, NAME, ARGS)                            \
+static QBasicAtomicPointer<TYPE > _k_static_##NAME = Q_BASIC_ATOMIC_INITIALIZER(0); \
+static bool _k_static_##NAME##_destroyed;                                      \
+static struct K_GLOBAL_STATIC_STRUCT_NAME(NAME)                                \
+{                                                                              \
+    bool isDestroyed()                                                         \
+    {                                                                          \
+        return _k_static_##NAME##_destroyed;                                   \
+    }                                                                          \
+    inline operator TYPE*()                                                    \
+    {                                                                          \
+        return operator->();                                                   \
+    }                                                                          \
+    inline TYPE *operator->()                                                  \
+    {                                                                          \
+        if (!_k_static_##NAME) {                                               \
+            if (isDestroyed()) {                                               \
+            qFatal("Fatal Error: Accessed global static '%s *%s()' after destruction. " \
+             "Defined at %s:%d", #TYPE, #NAME, __FILE__, __LINE__);		\
+	     }                                                                  \
+	     TYPE *x = new TYPE ARGS;                                           \
+	     if (!_k_static_##NAME.testAndSetOrdered(0, x)                      \
+	         && _k_static_##NAME != x ) {                                   \
+	         delete x;                                                      \
+	     } else { 								\
+		static CleanUpGlobalStatic cleanUpObject = { destroy };	\
+	     }   								\
+	 }                                                                      \
+         return _k_static_##NAME;                                               \
+    }            								\
+    inline TYPE &operator*()                                                   \
+    {                                                                          \
+        return *operator->();                                                  \
+    }                                                                          \
+    static void destroy()                                                      \
+    {                                                                          \
+        _k_static_##NAME##_destroyed = true;                                   \
+        TYPE *x = _k_static_##NAME;                                            \
+        _k_static_##NAME = 0;                                                  \
+        delete x;                                                              \
+    }                                                                          \
+} NAME;
+								
+								
+
+
+
+class QIODevice;
+class QTextStream;
+
+namespace Konsole
+{
+
+/** 
+ * A convertor which maps between key sequences pressed by the user and the
+ * character strings which should be sent to the terminal and commands
+ * which should be invoked when those character sequences are pressed.
+ *
+ * Konsole supports multiple keyboard translators, allowing the user to
+ * specify the character sequences which are sent to the terminal
+ * when particular key sequences are pressed.
+ *
+ * A key sequence is defined as a key code, associated keyboard modifiers
+ * (Shift,Ctrl,Alt,Meta etc.) and state flags which indicate the state
+ * which the terminal must be in for the key sequence to apply.
+ */
+class KeyboardTranslator
+{
+public:
+    /** 
+     * The meaning of a particular key sequence may depend upon the state which
+     * the terminal emulation is in.  Therefore findEntry() may return a different
+     * Entry depending upon the state flags supplied.
+     *
+     * This enum describes the states which may be associated with with a particular
+     * entry in the keyboard translation entry.
+     */
+    enum State
+    {
+        /** Indicates that no special state is active */
+        NoState = 0,
+        /**
+         * TODO More documentation
+         */
+        NewLineState = 1,
+        /** 
+         * Indicates that the terminal is in 'Ansi' mode.
+         * TODO: More documentation
+         */
+        AnsiState = 2,
+        /**
+         * TODO More documentation
+         */
+        CursorKeysState = 4,
+        /**
+         * Indicates that the alternate screen ( typically used by interactive programs
+         * such as screen or vim ) is active 
+         */
+        AlternateScreenState = 8,
+        /** Indicates that any of the modifier keys is active. */ 
+        AnyModifierState = 16
+    };
+    Q_DECLARE_FLAGS(States,State)
+
+    /**
+     * This enum describes commands which are associated with particular key sequences.
+     */
+    enum Command
+    {
+        /** Indicates that no command is associated with this command sequence */
+        NoCommand = 0,
+        /** TODO Document me */
+        SendCommand = 1,
+        /** Scroll the terminal display up one page */
+        ScrollPageUpCommand = 2,
+        /** Scroll the terminal display down one page */
+        ScrollPageDownCommand = 4,
+        /** Scroll the terminal display up one line */
+        ScrollLineUpCommand = 8,
+        /** Scroll the terminal display down one line */
+        ScrollLineDownCommand = 16,
+        /** Toggles scroll lock mode */
+        ScrollLockCommand = 32,
+		/** Echos the operating system specific erase character. */
+		EraseCommand = 64
+    };
+    Q_DECLARE_FLAGS(Commands,Command)
+
+    /**
+     * Represents an association between a key sequence pressed by the user
+     * and the character sequence and commands associated with it for a particular
+     * KeyboardTranslator.
+     */
+    class Entry
+    {
+    public:
+        /** 
+         * Constructs a new entry for a keyboard translator.
+         */
+        Entry();
+
+        /** 
+         * Returns true if this entry is null.
+         * This is true for newly constructed entries which have no properties set. 
+         */
+        bool isNull() const;
+
+        /** Returns the commands associated with this entry */
+        Command command() const;
+        /** Sets the command associated with this entry. */
+        void setCommand(Command command);
+
+        /** 
+         * Returns the character sequence associated with this entry, optionally replacing 
+         * wildcard '*' characters with numbers to indicate the keyboard modifiers being pressed.
+         *
+         * TODO: The numbers used to replace '*' characters are taken from the Konsole/KDE 3 code.
+         * Document them. 
+         *
+         * @param expandWildCards Specifies whether wild cards (occurrences of the '*' character) in
+         * the entry should be replaced with a number to indicate the modifier keys being pressed. 
+         *
+         * @param modifiers The keyboard modifiers being pressed.
+         */
+        QByteArray text(bool expandWildCards = false,
+                        Qt::KeyboardModifiers modifiers = Qt::NoModifier) const;
+
+        /** Sets the character sequence associated with this entry */
+        void setText(const QByteArray& text);
+
+        /** 
+         * Returns the character sequence associated with this entry,
+         * with any non-printable characters replaced with escape sequences.
+         *
+         * eg. \\E for Escape, \\t for tab, \\n for new line.
+         *
+         * @param expandWildCards See text()
+         * @param modifiers See text()
+         */
+        QByteArray escapedText(bool expandWildCards = false,
+                               Qt::KeyboardModifiers modifiers = Qt::NoModifier) const;
+
+        /** Returns the character code ( from the Qt::Key enum ) associated with this entry */
+        int keyCode() const;
+        /** Sets the character code associated with this entry */
+        void setKeyCode(int keyCode);
+
+        /** 
+         * Returns a bitwise-OR of the enabled keyboard modifiers associated with this entry. 
+         * If a modifier is set in modifierMask() but not in modifiers(), this means that the entry
+         * only matches when that modifier is NOT pressed.
+         *
+         * If a modifier is not set in modifierMask() then the entry matches whether the modifier
+         * is pressed or not. 
+         */
+        Qt::KeyboardModifiers modifiers() const;
+
+        /** Returns the keyboard modifiers which are valid in this entry.  See modifiers() */
+        Qt::KeyboardModifiers modifierMask() const;
+
+        /** See modifiers() */
+        void setModifiers( Qt::KeyboardModifiers modifiers );
+        /** See modifierMask() and modifiers() */
+        void setModifierMask( Qt::KeyboardModifiers modifiers );
+
+        /** 
+         * Returns a bitwise-OR of the enabled state flags associated with this entry. 
+         * If flag is set in stateMask() but not in state(), this means that the entry only 
+         * matches when the terminal is NOT in that state.
+         *
+         * If a state is not set in stateMask() then the entry matches whether the terminal
+         * is in that state or not. 
+         */
+        States state() const;
+
+        /** Returns the state flags which are valid in this entry.  See state() */
+        States stateMask() const;
+
+        /** See state() */
+        void setState( States state );
+        /** See stateMask() */
+        void setStateMask( States mask );
+
+        /** 
+         * Returns the key code and modifiers associated with this entry 
+         * as a QKeySequence
+         */
+        //QKeySequence keySequence() const;
+
+        /** 
+         * Returns this entry's conditions ( ie. its key code, modifier and state criteria )
+         * as a string.
+         */
+        QString conditionToString() const;
+
+        /**
+         * Returns this entry's result ( ie. its command or character sequence )
+         * as a string.
+         *
+         * @param expandWildCards See text()
+         * @param modifiers See text()
+         */
+        QString resultToString(bool expandWildCards = false,
+                               Qt::KeyboardModifiers modifiers = Qt::NoModifier) const;
+
+        /** 
+         * Returns true if this entry matches the given key sequence, specified
+         * as a combination of @p keyCode , @p modifiers and @p state.
+         */
+        bool matches( int keyCode , 
+                      Qt::KeyboardModifiers modifiers , 
+                      States flags ) const;
+
+        bool operator==(const Entry& rhs) const;
+       
+    private:
+        void insertModifier( QString& item , int modifier ) const;
+        void insertState( QString& item , int state ) const;
+        QByteArray unescape(const QByteArray& text) const;
+
+        int _keyCode;
+        Qt::KeyboardModifiers _modifiers;
+        Qt::KeyboardModifiers _modifierMask;
+        States _state;
+        States _stateMask;
+
+        Command _command;
+        QByteArray _text;
+    };
+
+    /** Constructs a new keyboard translator with the given @p name */
+    KeyboardTranslator(const QString& name);
+   
+    //KeyboardTranslator(const KeyboardTranslator& other);
+
+    /** Returns the name of this keyboard translator */
+    QString name() const;
+
+    /** Sets the name of this keyboard translator */
+    void setName(const QString& name);
+
+    /** Returns the descriptive name of this keyboard translator */
+    QString description() const;
+
+    /** Sets the descriptive name of this keyboard translator */
+    void setDescription(const QString& description);
+
+    /**
+     * Looks for an entry in this keyboard translator which matches the given
+     * key code, keyboard modifiers and state flags.
+     * 
+     * Returns the matching entry if found or a null Entry otherwise ( ie.
+     * entry.isNull() will return true )
+     *
+     * @param keyCode A key code from the Qt::Key enum
+     * @param modifiers A combination of modifiers
+     * @param state Optional flags which specify the current state of the terminal
+     */
+    Entry findEntry(int keyCode , 
+                    Qt::KeyboardModifiers modifiers , 
+                    States state = NoState) const;
+
+    /** 
+     * Adds an entry to this keyboard translator's table.  Entries can be looked up according
+     * to their key sequence using findEntry()
+     */
+    void addEntry(const Entry& entry);
+
+    /**
+     * Replaces an entry in the translator.  If the @p existing entry is null,
+     * then this is equivalent to calling addEntry(@p replacement)
+     */
+    void replaceEntry(const Entry& existing , const Entry& replacement);
+
+    /**
+     * Removes an entry from the table.
+     */
+    void removeEntry(const Entry& entry);
+
+    /** Returns a list of all entries in the translator. */
+    QList<Entry> entries() const;
+
+private:
+
+    QHash<int,Entry> _entries; // entries in this keyboard translation,
+                                                 // entries are indexed according to
+                                                 // their keycode
+    QString _name;
+    QString _description;
+};
+Q_DECLARE_OPERATORS_FOR_FLAGS(KeyboardTranslator::States)
+Q_DECLARE_OPERATORS_FOR_FLAGS(KeyboardTranslator::Commands)
+
+/** 
+ * Parses the contents of a Keyboard Translator (.keytab) file and 
+ * returns the entries found in it.
+ *
+ * Usage example:
+ *
+ * @code
+ *  QFile source( "/path/to/keytab" );
+ *  source.open( QIODevice::ReadOnly );
+ *
+ *  KeyboardTranslator* translator = new KeyboardTranslator( "name-of-translator" );
+ *
+ *  KeyboardTranslatorReader reader(source);
+ *  while ( reader.hasNextEntry() )
+ *      translator->addEntry(reader.nextEntry());
+ *
+ *  source.close();
+ *
+ *  if ( !reader.parseError() )
+ *  {
+ *      // parsing succeeded, do something with the translator
+ *  } 
+ *  else
+ *  {
+ *      // parsing failed
+ *  }
+ * @endcode
+ */
+class KeyboardTranslatorReader
+{
+public:
+    /** Constructs a new reader which parses the given @p source */
+    KeyboardTranslatorReader( QIODevice* source );
+
+    /** 
+     * Returns the description text. 
+     * TODO: More documentation 
+     */
+    QString description() const;
+
+    /** Returns true if there is another entry in the source stream */
+    bool hasNextEntry();
+    /** Returns the next entry found in the source stream */
+    KeyboardTranslator::Entry nextEntry(); 
+
+    /** 
+     * Returns true if an error occurred whilst parsing the input or
+     * false if no error occurred.
+     */
+    bool parseError();
+
+    /**
+     * Parses a condition and result string for a translator entry
+     * and produces a keyboard translator entry.
+     *
+     * The condition and result strings are in the same format as in  
+     */
+    static KeyboardTranslator::Entry createEntry( const QString& condition ,
+                                                  const QString& result );
+private:
+    struct Token
+    {
+        enum Type
+        {
+            TitleKeyword,
+            TitleText,
+            KeyKeyword,
+            KeySequence,
+            Command,
+            OutputText
+        };
+        Type type;
+        QString text;
+    };
+    QList<Token> tokenize(const QString&);
+    void readNext();
+    bool decodeSequence(const QString& , 
+                                int& keyCode,
+                                Qt::KeyboardModifiers& modifiers,
+                                Qt::KeyboardModifiers& modifierMask,
+                                KeyboardTranslator::States& state,
+                                KeyboardTranslator::States& stateFlags);
+
+    static bool parseAsModifier(const QString& item , Qt::KeyboardModifier& modifier);
+    static bool parseAsStateFlag(const QString& item , KeyboardTranslator::State& state);
+    static bool parseAsKeyCode(const QString& item , int& keyCode);
+   	static bool parseAsCommand(const QString& text , KeyboardTranslator::Command& command);
+
+    QIODevice* _source;
+    QString _description;
+    KeyboardTranslator::Entry _nextEntry;
+    bool _hasNext;
+};
+
+/** Writes a keyboard translation to disk. */
+class KeyboardTranslatorWriter
+{
+public:
+    /** 
+     * Constructs a new writer which saves data into @p destination.
+     * The caller is responsible for closing the device when writing is complete.
+     */
+    KeyboardTranslatorWriter(QIODevice* destination);
+    ~KeyboardTranslatorWriter();
+
+    /** 
+     * Writes the header for the keyboard translator. 
+     * @param description Description of the keyboard translator. 
+     */
+    void writeHeader( const QString& description );
+    /** Writes a translator entry. */
+    void writeEntry( const KeyboardTranslator::Entry& entry ); 
+
+private:
+    QIODevice* _destination;  
+    QTextStream* _writer;
+};
+
+/**
+ * Manages the keyboard translations available for use by terminal sessions,
+ * see KeyboardTranslator.
+ */
+class KeyboardTranslatorManager
+{
+public:
+    /** 
+     * Constructs a new KeyboardTranslatorManager and loads the list of
+     * available keyboard translations.
+     *
+     * The keyboard translations themselves are not loaded until they are
+     * first requested via a call to findTranslator()
+     */
+    KeyboardTranslatorManager();
+    ~KeyboardTranslatorManager();
+
+    /**
+     * Adds a new translator.  If a translator with the same name 
+     * already exists, it will be replaced by the new translator.
+     *
+     * TODO: More documentation.
+     */
+    void addTranslator(KeyboardTranslator* translator);
+
+    /**
+     * Deletes a translator.  Returns true on successful deletion or false otherwise.
+     *
+     * TODO: More documentation
+     */
+    bool deleteTranslator(const QString& name);
+
+    /** Returns the default translator for Konsole. */
+    const KeyboardTranslator* defaultTranslator();
+
+    /** 
+     * Returns the keyboard translator with the given name or 0 if no translator
+     * with that name exists.
+     *
+     * The first time that a translator with a particular name is requested,
+     * the on-disk .keyboard file is loaded and parsed.  
+     */
+    const KeyboardTranslator* findTranslator(const QString& name);
+    /**
+     * Returns a list of the names of available keyboard translators.
+     *
+     * The first time this is called, a search for available 
+     * translators is started.
+     */
+    QList<QString> allTranslators();
+
+    /** Returns the global KeyboardTranslatorManager instance. */
+   static KeyboardTranslatorManager* instance();
+
+private:
+    static const char* defaultTranslatorText;
+    
+    void findTranslators(); // locate the available translators
+    KeyboardTranslator* loadTranslator(const QString& name); // loads the translator 
+                                                             // with the given name
+    KeyboardTranslator* loadTranslator(QIODevice* device,const QString& name);
+
+    bool saveTranslator(const KeyboardTranslator* translator);
+    QString findTranslatorPath(const QString& name);
+    
+    QHash<QString,KeyboardTranslator*> _translators; // maps translator-name -> KeyboardTranslator
+                                                     // instance
+    bool _haveLoadedAll;
+};
+
+inline int KeyboardTranslator::Entry::keyCode() const { return _keyCode; }
+inline void KeyboardTranslator::Entry::setKeyCode(int keyCode) { _keyCode = keyCode; }
+
+inline void KeyboardTranslator::Entry::setModifiers( Qt::KeyboardModifiers modifier ) 
+{ 
+    _modifiers = modifier;
+}
+inline Qt::KeyboardModifiers KeyboardTranslator::Entry::modifiers() const { return _modifiers; }
+
+inline void  KeyboardTranslator::Entry::setModifierMask( Qt::KeyboardModifiers mask ) 
+{ 
+   _modifierMask = mask; 
+}
+inline Qt::KeyboardModifiers KeyboardTranslator::Entry::modifierMask() const { return _modifierMask; }
+
+inline bool KeyboardTranslator::Entry::isNull() const
+{
+    return ( *this == Entry() );
+}
+
+inline void KeyboardTranslator::Entry::setCommand( Command command )
+{ 
+    _command = command; 
+}
+inline KeyboardTranslator::Command KeyboardTranslator::Entry::command() const { return _command; }
+
+inline void KeyboardTranslator::Entry::setText( const QByteArray& text )
+{ 
+    _text = unescape(text);
+}
+inline int oneOrZero(int value)
+{
+    return value ? 1 : 0;
+}
+inline QByteArray KeyboardTranslator::Entry::text(bool expandWildCards,Qt::KeyboardModifiers modifiers) const 
+{
+    QByteArray expandedText = _text;
+    
+    if (expandWildCards)
+    {
+        int modifierValue = 1;
+        modifierValue += oneOrZero(modifiers & Qt::ShiftModifier);
+        modifierValue += oneOrZero(modifiers & Qt::AltModifier)     << 1;
+        modifierValue += oneOrZero(modifiers & Qt::ControlModifier) << 2;
+
+        for (int i=0;i<_text.length();i++) 
+        {
+            if (expandedText[i] == '*')
+                expandedText[i] = '0' + modifierValue;
+        }
+    }
+
+    return expandedText; 
+}
+
+inline void KeyboardTranslator::Entry::setState( States state )
+{ 
+    _state = state; 
+}
+inline KeyboardTranslator::States KeyboardTranslator::Entry::state() const { return _state; }
+
+inline void KeyboardTranslator::Entry::setStateMask( States stateMask )
+{ 
+    _stateMask = stateMask; 
+}
+inline KeyboardTranslator::States KeyboardTranslator::Entry::stateMask() const { return _stateMask; }
+
+}
+
+Q_DECLARE_METATYPE(Konsole::KeyboardTranslator::Entry)
+Q_DECLARE_METATYPE(const Konsole::KeyboardTranslator*)
+
+#endif // KEYBOARDTRANSLATOR_H
+
new file mode 100644
--- /dev/null
+++ b/gui//LineFont.h
@@ -0,0 +1,21 @@
+// WARNING: Autogenerated by "fontembedder ./linefont.src".
+// You probably do not want to hand-edit this!
+
+static const quint32 LineChars[] = {
+	0x00007c00, 0x000fffe0, 0x00421084, 0x00e739ce, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00427000, 0x004e7380, 0x00e77800, 0x00ef7bc0, 
+	0x00421c00, 0x00439ce0, 0x00e73c00, 0x00e7bde0, 0x00007084, 0x000e7384, 0x000079ce, 0x000f7bce, 
+	0x00001c84, 0x00039ce4, 0x00003dce, 0x0007bdee, 0x00427084, 0x004e7384, 0x004279ce, 0x00e77884, 
+	0x00e779ce, 0x004f7bce, 0x00ef7bc4, 0x00ef7bce, 0x00421c84, 0x00439ce4, 0x00423dce, 0x00e73c84, 
+	0x00e73dce, 0x0047bdee, 0x00e7bde4, 0x00e7bdee, 0x00427c00, 0x0043fce0, 0x004e7f80, 0x004fffe0, 
+	0x004fffe0, 0x00e7fde0, 0x006f7fc0, 0x00efffe0, 0x00007c84, 0x0003fce4, 0x000e7f84, 0x000fffe4, 
+	0x00007dce, 0x0007fdee, 0x000f7fce, 0x000fffee, 0x00427c84, 0x0043fce4, 0x004e7f84, 0x004fffe4, 
+	0x00427dce, 0x00e77c84, 0x00e77dce, 0x0047fdee, 0x004e7fce, 0x00e7fde4, 0x00ef7f84, 0x004fffee, 
+	0x00efffe4, 0x00e7fdee, 0x00ef7fce, 0x00efffee, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
+	0x000f83e0, 0x00a5294a, 0x004e1380, 0x00a57800, 0x00ad0bc0, 0x004390e0, 0x00a53c00, 0x00a5a1e0, 
+	0x000e1384, 0x0000794a, 0x000f0b4a, 0x000390e4, 0x00003d4a, 0x0007a16a, 0x004e1384, 0x00a5694a, 
+	0x00ad2b4a, 0x004390e4, 0x00a52d4a, 0x00a5a16a, 0x004f83e0, 0x00a57c00, 0x00ad83e0, 0x000f83e4, 
+	0x00007d4a, 0x000f836a, 0x004f93e4, 0x00a57d4a, 0x00ad836a, 0x00000000, 0x00000000, 0x00000000, 
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00001c00, 0x00001084, 0x00007000, 0x00421000, 
+	0x00039ce0, 0x000039ce, 0x000e7380, 0x00e73800, 0x000e7f80, 0x00e73884, 0x0003fce0, 0x004239ce
+};
new file mode 100644
--- /dev/null
+++ b/gui//LineFont.src
@@ -0,0 +1,786 @@
+#2500: single horizontal line
+2500
+     
+     
+-----
+     
+     
+
+#2501: triple horizontal line
+2501
+     
+-----
+-----
+-----
+     
+
+#2502: single vertical line
+2502
+  |  
+  |  
+  |  
+  |  
+  |  
+
+#2503: triple vertical line
+2503
+ ||| 
+ ||| 
+ ||| 
+ ||| 
+ ||| 
+
+#2504-250B are dashed - not handled
+
+#250C: top-left corner (lines on bottom + right)
+250C
+     
+     
+  .--
+  |  
+  |  
+
+#250D: as above, but top line triple-width
+250D
+     
+  .--
+  .--
+  |--
+  |  
+
+#250E: now the vert line triple-width
+250E
+     
+     
+ ..--
+ ||| 
+ ||| 
+
+#250F: and now both lines triple-width
+250F
+     
+ .___
+ |.--
+ ||._
+ ||| 
+
+#2510: top-right corner
+2510
+     
+     
+--.  
+  |  
+  |  
+
+2511
+     
+==.  
+==.  
+==|  
+  | 
+
+2512
+     
+     
+==.. 
+ ||| 
+ ||| 
+
+2513
+     
+===. 
+==.| 
+=.|| 
+ ||| 
+
+#2514: bottom-left corner
+2514
+  |  
+  |  
+  .==
+     
+     
+
+2515
+  |  
+  |==
+  |==
+  ===
+     
+
+
+2516
+ ||| 
+ ||| 
+ |.==
+     
+     
+
+2517
+ ||| 
+ ||.=
+ |.==
+ .===
+     
+
+#2518: bottm-right corner
+2518
+  |  
+  |  
+==.  
+     
+     
+
+2519
+  |  
+==|  
+==|  
+===  
+     
+
+
+251A
+ ||| 
+ ||| 
+==== 
+     
+     
+
+251B
+ ||| 
+=.|| 
+==.| 
+===. 
+     
+
+#251C: Join of vertical line and one from the right
+251C
+  |  
+  |  
+  |==
+  |  
+  |  
+
+251D
+  |  
+  |==
+  |==
+  |==
+  |  
+
+251E
+ ||| 
+ ||| 
+ ||==
+  |  
+  |  
+
+251F
+  |  
+  |  
+ ||==
+ ||| 
+ ||| 
+
+
+2520
+ ||| 
+ ||| 
+ ||==
+ ||| 
+ ||| 
+
+2521
+ ||| 
+ |||=
+ ||==
+ .|==
+  |  
+
+2522
+  |  
+ .|==
+ ||==
+ |||=
+ ||| 
+
+2523
+ ||| 
+ ||.=
+ ||==
+ ||.=
+ ||| 
+
+#2524: Join of vertical line and one from the left
+2524
+  |  
+  |  
+==|  
+  |  
+  |  
+
+2525
+  |  
+==|  
+==|  
+==|  
+  |  
+
+2526
+ ||| 
+ ||| 
+==+| 
+  |  
+  |  
+
+2527
+  |  
+  |  
+==+| 
+ ||| 
+ ||| 
+
+2528
+ ||| 
+ ||| 
+==+| 
+ ||| 
+ ||| 
+
+2529
+ ||| 
+=+|| 
+==+| 
+===+ 
+  |  
+
+252A
+  |  
+=+|| 
+==+| 
+===+ 
+ ||| 
+
+252B
+ |||
+=+|| 
+==+| 
+=+|| 
+ |||
+
+#252C: horizontal line joined to from below
+252C
+     
+     
+=====
+  |  
+  |  
+
+252D
+     
+===  
+==|==
+==|  
+  |  
+
+252E
+     
+  ===
+==|==
+  |==
+  |  
+
+252F
+     
+==+==
+==|==
+==|==
+  |  
+
+2530
+     
+=====
+=====
+==|==
+  |  
+
+2531
+     
+===| 
+==||=
+=||| 
+ ||| 
+
+2532
+     
+ |===
+=||==
+ ||==
+ ||  
+
+2533
+     
+=====
+==|==
+=+|+=
+ ||| 
+
+#2534: bottom line, connected to from top
+2534
+  |
+  |
+=====
+     
+     
+
+2535
+  |
+==|
+=====
+===  
+    
+
+2536
+  |
+  |==
+=====
+  ===
+     
+
+2537
+  |
+==|==
+=====
+=====
+     
+
+2538
+ |||
+ |||
+=====
+     
+     
+
+2539
+ |||
+==||
+=====
+===| 
+    
+
+
+253A
+ |||
+ ||==
+=|===
+ |===
+     
+
+253B
+ |||
+==|==
+=====
+=====
+     
+
+#253C: vertical + horizontal lines intersecting
+253C
+  |  
+  |  
+=====
+  |  
+  |
+
+253D
+  |  
+==|  
+=====
+==|  
+  |
+
+253E
+  |  
+  |==
+=====
+  |==
+  |
+
+253F
+  |  
+==|==
+=====
+==|==
+  |
+
+2540
+ ||| 
+ ||| 
+=====
+  |  
+  |
+
+2541
+  |  
+  |  
+=====
+ ||| 
+ |||
+
+2542
+ ||| 
+ ||| 
+=====
+ ||| 
+ |||
+
+2543
+ ||| 
+=|||
+=====
+==|+ 
+  |
+
+2544
+ ||| 
+ ||==
+=====
+  |==
+  |
+
+2545
+  |
+==|+ 
+=====
+=|||
+ ||| 
+
+2546
+  |
+  |==
+=====
+ ||==
+ ||| 
+
+2547
+ ||| 
+=|||=
+=====
+=|||=
+  | 
+
+2548
+  |  
+=|||=
+=====
+=|||=
+ |||
+
+2549
+ ||| 
+=||| 
+=====
+=||| 
+ |||
+
+254A
+ ||| 
+ |||=
+=====
+ |||=
+ |||
+
+254B
+ ||| 
+=|||=
+=====
+=|||=
+ |||
+
+#254C-254F are dashed
+2550
+     
+_____
+     
+_____
+     
+
+2551
+ | | 
+ | |
+ | |
+ | |
+ | |
+
+2552
+     
+  |--
+  |
+  |--
+  |
+
+2553
+     
+     
+ ----
+ | | 
+ | | 
+
+2554
+     
+ +---
+ |
+ + +-
+ | |
+
+2555
+     
+--+
+  |  
+--+  
+  |  
+
+2556
+    
+    
+-+-+
+ | |
+ | |
+
+2557
+     
+---+ 
+   | 
+-+ |
+ | |
+
+2558
+  |
+  +--
+  |
+  +--
+
+2559
+ | | 
+ | | 
+ +-+-
+     
+     
+
+255A
+ | | 
+ | +-
+ |   
+ +---
+     
+
+255B
+  |  
+--+  
+  | 
+--+  
+     
+
+255C
+ | | 
+ | | 
+-+-+ 
+    
+
+255D
+ | | 
+-+ | 
+   |
+---+
+    
+
+255E
+  |
+  +--
+  |
+  +--
+  |
+
+255F
+ | |
+ | |
+ | +-
+ | |
+ | |
+
+2560
+ | |
+ | +-
+ | |
+ | +-
+ | |
+
+2561
+  |
+--+
+  |
+--+
+  |
+
+2562
+ | | 
+ | |
+-+ +
+ | |
+ | |
+
+2563
+ | |
+-+ |
+   |
+-+ |
+ | |
+
+2564
+     
+-----
+     
+--+--
+  |
+
+2565
+     
+     
+-+-+-
+ | | 
+ | |
+
+2566
+     
+-----
+     
+-+ +-
+ | |
+
+2567
+  |  
+--+--
+     
+-----
+     
+
+2568
+ | | 
+ | | 
+-+-+-
+     
+     
+
+2569
+ | | 
+-+ +-
+     
+-----
+     
+
+256A
+  |  
+--+--
+  |  
+--+--
+  |
+
+256B
+ | | 
+ | | 
+-+-+-
+ | | 
+ | | 
+
+256C
+ | | 
+-+ +-
+
+-+ +-
+ | | 
+
+#256F-2570 are curly,
+#2571-2573 are slashes and X
+
+2574
+     
+     
+___  
+     
+     
+
+2575
+  |  
+  |  
+  |  
+     
+    
+
+2576
+     
+     
+  ___
+     
+     
+
+2577
+     
+    
+  |  
+  |  
+  |  
+
+2578
+     
+___  
+___  
+___  
+     
+
+2579
+ ||| 
+ ||| 
+ ||| 
+     
+    
+
+257A
+     
+  ___
+  ___
+  ___
+     
+
+257B
+     
+    
+ ||| 
+ ||| 
+ ||| 
+
+257C
+     
+  ___
+_____
+  ___
+     
+
+257D
+  |  
+  |  
+ ||| 
+ ||| 
+ ||| 
+
+257E
+     
+___  
+_____
+___  
+     
+
+257F
+ ||| 
+ ||| 
+ ||| 
+  |  
+  |  
new file mode 100644
--- /dev/null
+++ b/gui//Makefile
@@ -0,0 +1,494 @@
+#############################################################################
+# Makefile for building: Quint
+# Generated by qmake (2.01a) (Qt 4.7.2) on: Do. Apr 7 11:59:45 2011
+# Project:  Quint.pro
+# Template: app
+# Command: /usr/bin/qmake -o Makefile Quint.pro
+#############################################################################
+
+####### Compiler, tools and options
+
+CC            = gcc
+CXX           = g++
+DEFINES       = -DHAVE_POSIX_OPENPT -DQT_NO_DEBUG -DQT_WEBKIT_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_SHARED
+CFLAGS        = -pipe -O2 -Wall -W -D_REENTRANT $(DEFINES)
+CXXFLAGS      = -pipe -O2 -Wall -W -D_REENTRANT $(DEFINES)
+INCPATH       = -I/usr/share/qt4/mkspecs/linux-g++ -I. -I/usr/include/qt4/QtCore -I/usr/include/qt4/QtGui -I/usr/include/qt4/QtWebKit -I/usr/include/qt4 -I.
+LINK          = g++
+LFLAGS        = -Wl,-O1
+LIBS          = $(SUBLIBS)  -L/usr/lib -lQtWebKit -lQtGui -lQtCore -lpthread 
+AR            = ar cqs
+RANLIB        = 
+QMAKE         = /usr/bin/qmake
+TAR           = tar -cf
+COMPRESS      = gzip -9f
+COPY          = cp -f
+SED           = sed
+COPY_FILE     = $(COPY)
+COPY_DIR      = $(COPY) -r
+STRIP         = strip
+INSTALL_FILE  = install -m 644 -p
+INSTALL_DIR   = $(COPY_DIR)
+INSTALL_PROGRAM = install -m 755 -p
+DEL_FILE      = rm -f
+SYMLINK       = ln -f -s
+DEL_DIR       = rmdir
+MOVE          = mv -f
+CHK_DIR_EXISTS= test -d
+MKDIR         = mkdir -p
+
+####### Output directory
+
+OBJECTS_DIR   = ./
+
+####### Files
+
+SOURCES       = main.cpp \
+		mainwindow.cpp \
+		terminal.cpp \
+		TerminalCharacterDecoder.cpp \
+		KeyboardTranslator.cpp \
+		Screen.cpp \
+		History.cpp \
+		BlockArray.cpp \
+		konsole_wcwidth.cpp \
+		ScreenWindow.cpp \
+		Emulation.cpp \
+		Vt102Emulation.cpp \
+		TerminalDisplay.cpp \
+		Filter.cpp \
+		Pty.cpp \
+		kpty.cpp \
+		k3process.cpp \
+		k3processcontroller.cpp \
+		Session.cpp \
+		ShellCommand.cpp \
+		qtermwidget.cpp moc_mainwindow.cpp \
+		moc_terminal.cpp \
+		moc_ScreenWindow.cpp \
+		moc_Emulation.cpp \
+		moc_Vt102Emulation.cpp \
+		moc_TerminalDisplay.cpp \
+		moc_Filter.cpp \
+		moc_Pty.cpp \
+		moc_k3process.cpp \
+		moc_k3processcontroller.cpp \
+		moc_Session.cpp \
+		moc_qtermwidget.cpp
+OBJECTS       = main.o \
+		mainwindow.o \
+		terminal.o \
+		TerminalCharacterDecoder.o \
+		KeyboardTranslator.o \
+		Screen.o \
+		History.o \
+		BlockArray.o \
+		konsole_wcwidth.o \
+		ScreenWindow.o \
+		Emulation.o \
+		Vt102Emulation.o \
+		TerminalDisplay.o \
+		Filter.o \
+		Pty.o \
+		kpty.o \
+		k3process.o \
+		k3processcontroller.o \
+		Session.o \
+		ShellCommand.o \
+		qtermwidget.o \
+		moc_mainwindow.o \
+		moc_terminal.o \
+		moc_ScreenWindow.o \
+		moc_Emulation.o \
+		moc_Vt102Emulation.o \
+		moc_TerminalDisplay.o \
+		moc_Filter.o \
+		moc_Pty.o \
+		moc_k3process.o \
+		moc_k3processcontroller.o \
+		moc_Session.o \
+		moc_qtermwidget.o
+DIST          = /usr/share/qt4/mkspecs/common/g++.conf \
+		/usr/share/qt4/mkspecs/common/unix.conf \
+		/usr/share/qt4/mkspecs/common/linux.conf \
+		/usr/share/qt4/mkspecs/qconfig.pri \
+		/usr/share/qt4/mkspecs/modules/qt_webkit_version.pri \
+		/usr/share/qt4/mkspecs/features/qt_functions.prf \
+		/usr/share/qt4/mkspecs/features/qt_config.prf \
+		/usr/share/qt4/mkspecs/features/exclusive_builds.prf \
+		/usr/share/qt4/mkspecs/features/default_pre.prf \
+		/usr/share/qt4/mkspecs/features/release.prf \
+		/usr/share/qt4/mkspecs/features/default_post.prf \
+		/usr/share/qt4/mkspecs/features/warn_on.prf \
+		/usr/share/qt4/mkspecs/features/qt.prf \
+		/usr/share/qt4/mkspecs/features/unix/thread.prf \
+		/usr/share/qt4/mkspecs/features/moc.prf \
+		/usr/share/qt4/mkspecs/features/resources.prf \
+		/usr/share/qt4/mkspecs/features/uic.prf \
+		/usr/share/qt4/mkspecs/features/yacc.prf \
+		/usr/share/qt4/mkspecs/features/lex.prf \
+		/usr/share/qt4/mkspecs/features/include_source_dir.prf \
+		Quint.pro
+QMAKE_TARGET  = Quint
+DESTDIR       = 
+TARGET        = Quint
+
+first: all
+####### Implicit rules
+
+.SUFFIXES: .o .c .cpp .cc .cxx .C
+
+.cpp.o:
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o "$@" "$<"
+
+.cc.o:
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o "$@" "$<"
+
+.cxx.o:
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o "$@" "$<"
+
+.C.o:
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o "$@" "$<"
+
+.c.o:
+	$(CC) -c $(CFLAGS) $(INCPATH) -o "$@" "$<"
+
+####### Build rules
+
+all: Makefile $(TARGET)
+
+$(TARGET):  $(OBJECTS)  
+	$(LINK) $(LFLAGS) -o $(TARGET) $(OBJECTS) $(OBJCOMP) $(LIBS)
+
+Makefile: Quint.pro  /usr/share/qt4/mkspecs/linux-g++/qmake.conf /usr/share/qt4/mkspecs/common/g++.conf \
+		/usr/share/qt4/mkspecs/common/unix.conf \
+		/usr/share/qt4/mkspecs/common/linux.conf \
+		/usr/share/qt4/mkspecs/qconfig.pri \
+		/usr/share/qt4/mkspecs/modules/qt_webkit_version.pri \
+		/usr/share/qt4/mkspecs/features/qt_functions.prf \
+		/usr/share/qt4/mkspecs/features/qt_config.prf \
+		/usr/share/qt4/mkspecs/features/exclusive_builds.prf \
+		/usr/share/qt4/mkspecs/features/default_pre.prf \
+		/usr/share/qt4/mkspecs/features/release.prf \
+		/usr/share/qt4/mkspecs/features/default_post.prf \
+		/usr/share/qt4/mkspecs/features/warn_on.prf \
+		/usr/share/qt4/mkspecs/features/qt.prf \
+		/usr/share/qt4/mkspecs/features/unix/thread.prf \
+		/usr/share/qt4/mkspecs/features/moc.prf \
+		/usr/share/qt4/mkspecs/features/resources.prf \
+		/usr/share/qt4/mkspecs/features/uic.prf \
+		/usr/share/qt4/mkspecs/features/yacc.prf \
+		/usr/share/qt4/mkspecs/features/lex.prf \
+		/usr/share/qt4/mkspecs/features/include_source_dir.prf \
+		/usr/lib/libQtWebKit.prl \
+		/usr/lib/libQtGui.prl \
+		/usr/lib/libQtCore.prl
+	$(QMAKE) -o Makefile Quint.pro
+/usr/share/qt4/mkspecs/common/g++.conf:
+/usr/share/qt4/mkspecs/common/unix.conf:
+/usr/share/qt4/mkspecs/common/linux.conf:
+/usr/share/qt4/mkspecs/qconfig.pri:
+/usr/share/qt4/mkspecs/modules/qt_webkit_version.pri:
+/usr/share/qt4/mkspecs/features/qt_functions.prf:
+/usr/share/qt4/mkspecs/features/qt_config.prf:
+/usr/share/qt4/mkspecs/features/exclusive_builds.prf:
+/usr/share/qt4/mkspecs/features/default_pre.prf:
+/usr/share/qt4/mkspecs/features/release.prf:
+/usr/share/qt4/mkspecs/features/default_post.prf:
+/usr/share/qt4/mkspecs/features/warn_on.prf:
+/usr/share/qt4/mkspecs/features/qt.prf:
+/usr/share/qt4/mkspecs/features/unix/thread.prf:
+/usr/share/qt4/mkspecs/features/moc.prf:
+/usr/share/qt4/mkspecs/features/resources.prf:
+/usr/share/qt4/mkspecs/features/uic.prf:
+/usr/share/qt4/mkspecs/features/yacc.prf:
+/usr/share/qt4/mkspecs/features/lex.prf:
+/usr/share/qt4/mkspecs/features/include_source_dir.prf:
+/usr/lib/libQtWebKit.prl:
+/usr/lib/libQtGui.prl:
+/usr/lib/libQtCore.prl:
+qmake:  FORCE
+	@$(QMAKE) -o Makefile Quint.pro
+
+dist: 
+	@$(CHK_DIR_EXISTS) .tmp/Quint1.0.0 || $(MKDIR) .tmp/Quint1.0.0 
+	$(COPY_FILE) --parents $(SOURCES) $(DIST) .tmp/Quint1.0.0/ && $(COPY_FILE) --parents mainwindow.h terminal.h TerminalCharacterDecoder.h Character.h CharacterColor.h KeyboardTranslator.h ExtendedDefaultTranslator.h Screen.h History.h BlockArray.h konsole_wcwidth.h ScreenWindow.h Emulation.h Vt102Emulation.h TerminalDisplay.h Filter.h LineFont.h Pty.h kpty.h kpty_p.h k3process.h k3processcontroller.h Session.h ShellCommand.h qtermwidget.h .tmp/Quint1.0.0/ && $(COPY_FILE) --parents main.cpp mainwindow.cpp terminal.cpp TerminalCharacterDecoder.cpp KeyboardTranslator.cpp Screen.cpp History.cpp BlockArray.cpp konsole_wcwidth.cpp ScreenWindow.cpp Emulation.cpp Vt102Emulation.cpp TerminalDisplay.cpp Filter.cpp Pty.cpp kpty.cpp k3process.cpp k3processcontroller.cpp Session.cpp ShellCommand.cpp qtermwidget.cpp .tmp/Quint1.0.0/ && (cd `dirname .tmp/Quint1.0.0` && $(TAR) Quint1.0.0.tar Quint1.0.0 && $(COMPRESS) Quint1.0.0.tar) && $(MOVE) `dirname .tmp/Quint1.0.0`/Quint1.0.0.tar.gz . && $(DEL_FILE) -r .tmp/Quint1.0.0
+
+
+clean:compiler_clean 
+	-$(DEL_FILE) $(OBJECTS)
+	-$(DEL_FILE) *~ core *.core
+
+
+####### Sub-libraries
+
+distclean: clean
+	-$(DEL_FILE) $(TARGET) 
+	-$(DEL_FILE) Makefile
+
+
+check: first
+
+mocclean: compiler_moc_header_clean compiler_moc_source_clean
+
+mocables: compiler_moc_header_make_all compiler_moc_source_make_all
+
+compiler_moc_header_make_all: moc_mainwindow.cpp moc_terminal.cpp moc_ScreenWindow.cpp moc_Emulation.cpp moc_Vt102Emulation.cpp moc_TerminalDisplay.cpp moc_Filter.cpp moc_Pty.cpp moc_k3process.cpp moc_k3processcontroller.cpp moc_Session.cpp moc_qtermwidget.cpp
+compiler_moc_header_clean:
+	-$(DEL_FILE) moc_mainwindow.cpp moc_terminal.cpp moc_ScreenWindow.cpp moc_Emulation.cpp moc_Vt102Emulation.cpp moc_TerminalDisplay.cpp moc_Filter.cpp moc_Pty.cpp moc_k3process.cpp moc_k3processcontroller.cpp moc_Session.cpp moc_qtermwidget.cpp
+moc_mainwindow.cpp: mainwindow.h
+	/usr/bin/moc-qt4 $(DEFINES) $(INCPATH) mainwindow.h -o moc_mainwindow.cpp
+
+moc_terminal.cpp: qtermwidget.h \
+		terminal.h
+	/usr/bin/moc-qt4 $(DEFINES) $(INCPATH) terminal.h -o moc_terminal.cpp
+
+moc_ScreenWindow.cpp: Character.h \
+		CharacterColor.h \
+		ScreenWindow.h
+	/usr/bin/moc-qt4 $(DEFINES) $(INCPATH) ScreenWindow.h -o moc_ScreenWindow.cpp
+
+moc_Emulation.cpp: Emulation.h
+	/usr/bin/moc-qt4 $(DEFINES) $(INCPATH) Emulation.h -o moc_Emulation.cpp
+
+moc_Vt102Emulation.cpp: Emulation.h \
+		Screen.h \
+		Character.h \
+		CharacterColor.h \
+		History.h \
+		BlockArray.h \
+		Vt102Emulation.h
+	/usr/bin/moc-qt4 $(DEFINES) $(INCPATH) Vt102Emulation.h -o moc_Vt102Emulation.cpp
+
+moc_TerminalDisplay.cpp: Filter.h \
+		Character.h \
+		CharacterColor.h \
+		ColorTables.h \
+		TerminalDisplay.h
+	/usr/bin/moc-qt4 $(DEFINES) $(INCPATH) TerminalDisplay.h -o moc_TerminalDisplay.cpp
+
+moc_Filter.cpp: Character.h \
+		CharacterColor.h \
+		Filter.h
+	/usr/bin/moc-qt4 $(DEFINES) $(INCPATH) Filter.h -o moc_Filter.cpp
+
+moc_Pty.cpp: k3process.h \
+		Pty.h
+	/usr/bin/moc-qt4 $(DEFINES) $(INCPATH) Pty.h -o moc_Pty.cpp
+
+moc_k3process.cpp: k3process.h
+	/usr/bin/moc-qt4 $(DEFINES) $(INCPATH) k3process.h -o moc_k3process.cpp
+
+moc_k3processcontroller.cpp: k3process.h \
+		k3processcontroller.h
+	/usr/bin/moc-qt4 $(DEFINES) $(INCPATH) k3processcontroller.h -o moc_k3processcontroller.cpp
+
+moc_Session.cpp: History.h \
+		BlockArray.h \
+		Character.h \
+		CharacterColor.h \
+		Session.h
+	/usr/bin/moc-qt4 $(DEFINES) $(INCPATH) Session.h -o moc_Session.cpp
+
+moc_qtermwidget.cpp: qtermwidget.h
+	/usr/bin/moc-qt4 $(DEFINES) $(INCPATH) qtermwidget.h -o moc_qtermwidget.cpp
+
+compiler_rcc_make_all:
+compiler_rcc_clean:
+compiler_image_collection_make_all: qmake_image_collection.cpp
+compiler_image_collection_clean:
+	-$(DEL_FILE) qmake_image_collection.cpp
+compiler_moc_source_make_all:
+compiler_moc_source_clean:
+compiler_uic_make_all:
+compiler_uic_clean:
+compiler_yacc_decl_make_all:
+compiler_yacc_decl_clean:
+compiler_yacc_impl_make_all:
+compiler_yacc_impl_clean:
+compiler_lex_make_all:
+compiler_lex_clean:
+compiler_clean: compiler_moc_header_clean 
+
+####### Compile
+
+main.o: main.cpp mainwindow.h
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o main.o main.cpp
+
+mainwindow.o: mainwindow.cpp mainwindow.h \
+		terminal.h \
+		qtermwidget.h
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o mainwindow.o mainwindow.cpp
+
+terminal.o: terminal.cpp terminal.h \
+		qtermwidget.h
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o terminal.o terminal.cpp
+
+TerminalCharacterDecoder.o: TerminalCharacterDecoder.cpp TerminalCharacterDecoder.h \
+		Character.h \
+		CharacterColor.h
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o TerminalCharacterDecoder.o TerminalCharacterDecoder.cpp
+
+KeyboardTranslator.o: KeyboardTranslator.cpp KeyboardTranslator.h \
+		ExtendedDefaultTranslator.h
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o KeyboardTranslator.o KeyboardTranslator.cpp
+
+Screen.o: Screen.cpp Screen.h \
+		Character.h \
+		CharacterColor.h \
+		History.h \
+		BlockArray.h \
+		konsole_wcwidth.h \
+		TerminalCharacterDecoder.h
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o Screen.o Screen.cpp
+
+History.o: History.cpp History.h \
+		BlockArray.h \
+		Character.h \
+		CharacterColor.h
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o History.o History.cpp
+
+BlockArray.o: BlockArray.cpp BlockArray.h
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o BlockArray.o BlockArray.cpp
+
+konsole_wcwidth.o: konsole_wcwidth.cpp konsole_wcwidth.h
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o konsole_wcwidth.o konsole_wcwidth.cpp
+
+ScreenWindow.o: ScreenWindow.cpp ScreenWindow.h \
+		Character.h \
+		CharacterColor.h \
+		Screen.h \
+		History.h \
+		BlockArray.h
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o ScreenWindow.o ScreenWindow.cpp
+
+Emulation.o: Emulation.cpp Emulation.h \
+		KeyboardTranslator.h \
+		Screen.h \
+		Character.h \
+		CharacterColor.h \
+		History.h \
+		BlockArray.h \
+		TerminalCharacterDecoder.h \
+		ScreenWindow.h
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o Emulation.o Emulation.cpp
+
+Vt102Emulation.o: Vt102Emulation.cpp Vt102Emulation.h \
+		Emulation.h \
+		Screen.h \
+		Character.h \
+		CharacterColor.h \
+		History.h \
+		BlockArray.h \
+		KeyboardTranslator.h
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o Vt102Emulation.o Vt102Emulation.cpp
+
+TerminalDisplay.o: TerminalDisplay.cpp TerminalDisplay.h \
+		Filter.h \
+		Character.h \
+		CharacterColor.h \
+		ColorTables.h \
+		konsole_wcwidth.h \
+		ScreenWindow.h \
+		TerminalCharacterDecoder.h \
+		LineFont.h
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o TerminalDisplay.o TerminalDisplay.cpp
+
+Filter.o: Filter.cpp Filter.h \
+		Character.h \
+		CharacterColor.h \
+		TerminalCharacterDecoder.h
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o Filter.o Filter.cpp
+
+Pty.o: Pty.cpp Pty.h \
+		k3process.h \
+		kpty.h
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o Pty.o Pty.cpp
+
+kpty.o: kpty.cpp kpty_p.h \
+		kpty.h
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o kpty.o kpty.cpp
+
+k3process.o: k3process.cpp k3process.h \
+		k3processcontroller.h \
+		kpty.h
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o k3process.o k3process.cpp
+
+k3processcontroller.o: k3processcontroller.cpp k3processcontroller.h \
+		k3process.h
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o k3processcontroller.o k3processcontroller.cpp
+
+Session.o: Session.cpp Session.h \
+		History.h \
+		BlockArray.h \
+		Character.h \
+		CharacterColor.h \
+		Pty.h \
+		k3process.h \
+		TerminalDisplay.h \
+		Filter.h \
+		ColorTables.h \
+		ShellCommand.h \
+		Vt102Emulation.h \
+		Emulation.h \
+		Screen.h
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o Session.o Session.cpp
+
+ShellCommand.o: ShellCommand.cpp ShellCommand.h
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o ShellCommand.o ShellCommand.cpp
+
+qtermwidget.o: qtermwidget.cpp qtermwidget.h \
+		Session.h \
+		History.h \
+		BlockArray.h \
+		Character.h \
+		CharacterColor.h \
+		TerminalDisplay.h \
+		Filter.h \
+		ColorTables.h
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o qtermwidget.o qtermwidget.cpp
+
+moc_mainwindow.o: moc_mainwindow.cpp 
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o moc_mainwindow.o moc_mainwindow.cpp
+
+moc_terminal.o: moc_terminal.cpp 
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o moc_terminal.o moc_terminal.cpp
+
+moc_ScreenWindow.o: moc_ScreenWindow.cpp 
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o moc_ScreenWindow.o moc_ScreenWindow.cpp
+
+moc_Emulation.o: moc_Emulation.cpp 
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o moc_Emulation.o moc_Emulation.cpp
+
+moc_Vt102Emulation.o: moc_Vt102Emulation.cpp 
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o moc_Vt102Emulation.o moc_Vt102Emulation.cpp
+
+moc_TerminalDisplay.o: moc_TerminalDisplay.cpp 
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o moc_TerminalDisplay.o moc_TerminalDisplay.cpp
+
+moc_Filter.o: moc_Filter.cpp 
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o moc_Filter.o moc_Filter.cpp
+
+moc_Pty.o: moc_Pty.cpp 
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o moc_Pty.o moc_Pty.cpp
+
+moc_k3process.o: moc_k3process.cpp 
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o moc_k3process.o moc_k3process.cpp
+
+moc_k3processcontroller.o: moc_k3processcontroller.cpp 
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o moc_k3processcontroller.o moc_k3processcontroller.cpp
+
+moc_Session.o: moc_Session.cpp 
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o moc_Session.o moc_Session.cpp
+
+moc_qtermwidget.o: moc_qtermwidget.cpp 
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o moc_qtermwidget.o moc_qtermwidget.cpp
+
+####### Install
+
+install:   FORCE
+
+uninstall:   FORCE
+
+FORCE:
+
new file mode 100644
--- /dev/null
+++ b/gui//Pty.cpp
@@ -0,0 +1,320 @@
+/*
+    This file is part of Konsole, an X terminal.
+    Copyright (C) 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
+
+    Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301  USA.
+*/
+
+// Own
+#include "Pty.h"
+
+// System
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+#include <termios.h>
+
+// Qt
+#include <QtCore>
+
+// KDE
+//#include <KStandardDirs>
+//#include <KLocale>
+//#include <KDebug>
+#include "kpty.h"
+
+using namespace Konsole;
+
+void Pty::donePty()
+{
+  emit done(exitStatus());
+}
+
+void Pty::setWindowSize(int lines, int cols)
+{
+  _windowColumns = cols;
+  _windowLines = lines;
+
+  if (pty()->masterFd() >= 0)
+    pty()->setWinSize(lines, cols);
+}
+QSize Pty::windowSize() const
+{
+    return QSize(_windowColumns,_windowLines);
+}
+
+void Pty::setXonXoff(bool enable)
+{
+  _xonXoff = enable;
+
+  if (pty()->masterFd() >= 0)
+  {
+    struct ::termios ttmode;
+    pty()->tcGetAttr(&ttmode);
+    if (!enable)
+      ttmode.c_iflag &= ~(IXOFF | IXON);
+    else
+      ttmode.c_iflag |= (IXOFF | IXON);
+    if (!pty()->tcSetAttr(&ttmode))
+      qWarning("Unable to set terminal attributes.");
+  }
+}
+
+void Pty::setUtf8Mode(bool enable)
+{
+#ifdef IUTF8 // XXX not a reasonable place to check it.
+  _utf8 = enable;
+
+  if (pty()->masterFd() >= 0)
+  {
+    struct ::termios ttmode;
+    pty()->tcGetAttr(&ttmode);
+    if (!enable)
+      ttmode.c_iflag &= ~IUTF8;
+    else
+      ttmode.c_iflag |= IUTF8;
+    if (!pty()->tcSetAttr(&ttmode))
+      qWarning("Unable to set terminal attributes.");
+  }
+#endif
+}
+
+void Pty::setErase(char erase)
+{
+  _eraseChar = erase;
+  
+  if (pty()->masterFd() >= 0)
+  {
+    struct ::termios ttmode;
+
+    pty()->tcGetAttr(&ttmode);
+
+    ttmode.c_cc[VERASE] = erase;
+
+    if (!pty()->tcSetAttr(&ttmode))
+      qWarning("Unable to set terminal attributes.");
+  }  
+}
+
+char Pty::erase() const
+{
+	if (pty()->masterFd() >= 0)
+	{
+		qDebug() << "Getting erase char";
+		struct ::termios ttyAttributes;
+		pty()->tcGetAttr(&ttyAttributes);
+		return ttyAttributes.c_cc[VERASE];
+	}
+
+	return _eraseChar;
+}
+
+void Pty::addEnvironmentVariables(const QStringList& environment)
+{
+    QListIterator<QString> iter(environment);
+    while (iter.hasNext())
+    {
+        QString pair = iter.next();
+
+        // split on the first '=' character
+        int pos = pair.indexOf('=');
+        
+        if ( pos >= 0 )
+        {
+            QString variable = pair.left(pos);
+            QString value = pair.mid(pos+1);
+
+            //kDebug() << "Setting environment pair" << variable <<
+            //    " set to " << value;
+
+            setEnvironment(variable,value);
+        }
+    }
+}
+
+int Pty::start(const QString& program, 
+               const QStringList& programArguments, 
+               const QStringList& environment, 
+               ulong winid, 
+               bool addToUtmp
+//               const QString& dbusService, 
+//               const QString& dbusSession)
+		)
+{
+  clearArguments();
+
+  setBinaryExecutable(program.toLatin1());
+
+  addEnvironmentVariables(environment);
+
+  QStringListIterator it( programArguments );
+  while (it.hasNext())
+    arguments.append( it.next().toUtf8() );
+
+//  if ( !dbusService.isEmpty() )
+//     setEnvironment("KONSOLE_DBUS_SERVICE",dbusService);
+//  if ( !dbusSession.isEmpty() )
+//     setEnvironment("KONSOLE_DBUS_SESSION", dbusSession);
+
+  setEnvironment("WINDOWID", QString::number(winid));
+
+  // unless the LANGUAGE environment variable has been set explicitly
+  // set it to a null string
+  // this fixes the problem where KCatalog sets the LANGUAGE environment
+  // variable during the application's startup to something which
+  // differs from LANG,LC_* etc. and causes programs run from
+  // the terminal to display mesages in the wrong language
+  //
+  // this can happen if LANG contains a language which KDE
+  // does not have a translation for
+  //
+  // BR:149300
+  if (!environment.contains("LANGUAGE"))
+      setEnvironment("LANGUAGE",QString());
+
+  setUsePty(All, addToUtmp);
+
+  pty()->open();
+  
+  struct ::termios ttmode;
+  pty()->tcGetAttr(&ttmode);
+  if (!_xonXoff)
+    ttmode.c_iflag &= ~(IXOFF | IXON);
+  else
+    ttmode.c_iflag |= (IXOFF | IXON);
+#ifdef IUTF8 // XXX not a reasonable place to check it.
+  if (!_utf8)
+    ttmode.c_iflag &= ~IUTF8;
+  else
+    ttmode.c_iflag |= IUTF8;
+#endif
+
+  if (_eraseChar != 0)
+  	ttmode.c_cc[VERASE] = _eraseChar;
+  
+  if (!pty()->tcSetAttr(&ttmode))
+    qWarning("Unable to set terminal attributes.");
+  
+  pty()->setWinSize(_windowLines, _windowColumns);
+
+  if ( K3Process::start(NotifyOnExit, (Communication) (Stdin | Stdout)) == false )
+     return -1;
+
+  resume(); // Start...
+  return 0;
+
+}
+
+void Pty::setWriteable(bool writeable)
+{
+  struct stat sbuf;
+  stat(pty()->ttyName(), &sbuf);
+  if (writeable)
+    chmod(pty()->ttyName(), sbuf.st_mode | S_IWGRP);
+  else
+    chmod(pty()->ttyName(), sbuf.st_mode & ~(S_IWGRP|S_IWOTH));
+}
+
+Pty::Pty()
+    : _bufferFull(false),
+      _windowColumns(0),
+      _windowLines(0),
+      _eraseChar(0),
+      _xonXoff(true),
+      _utf8(true)
+{
+  connect(this, SIGNAL(receivedStdout(K3Process *, char *, int )),
+	  this, SLOT(dataReceived(K3Process *,char *, int)));
+  connect(this, SIGNAL(processExited(K3Process *)),
+          this, SLOT(donePty()));
+  connect(this, SIGNAL(wroteStdin(K3Process *)),
+          this, SLOT(writeReady()));
+  _pty = new KPty;
+
+  setUsePty(All, false); // utmp will be overridden later
+}
+
+Pty::~Pty()
+{
+    delete _pty;
+}
+
+void Pty::writeReady()
+{
+  _pendingSendJobs.erase(_pendingSendJobs.begin());
+  _bufferFull = false;
+  doSendJobs();
+}
+
+void Pty::doSendJobs() {
+  if(_pendingSendJobs.isEmpty())
+  {
+     emit bufferEmpty(); 
+     return;
+  }
+  
+  SendJob& job = _pendingSendJobs.first();
+
+  
+  if (!writeStdin( job.data(), job.length() ))
+  {
+    qWarning("Pty::doSendJobs - Could not send input data to terminal process.");
+    return;
+  }
+  _bufferFull = true;
+}
+
+void Pty::appendSendJob(const char* s, int len)
+{
+  _pendingSendJobs.append(SendJob(s,len));
+}
+
+void Pty::sendData(const char* s, int len)
+{
+  appendSendJob(s,len);
+  if (!_bufferFull)
+     doSendJobs();
+}
+
+void Pty::dataReceived(K3Process *,char *buf, int len)
+{
+  emit receivedData(buf,len);
+}
+
+void Pty::lockPty(bool lock)
+{
+  if (lock)
+    suspend();
+  else
+    resume();
+}
+
+int Pty::foregroundProcessGroup() const
+{
+    int pid = tcgetpgrp(pty()->masterFd());
+
+    if ( pid != -1 )
+    {
+        return pid;
+    } 
+
+    return 0;
+}
+
+//#include "moc_Pty.cpp"
new file mode 100644
--- /dev/null
+++ b/gui//Pty.h
@@ -0,0 +1,243 @@
+/*
+    This file is part of Konsole, KDE's terminal emulator. 
+    
+    Copyright (C) 2007 by Robert Knight <robertknight@gmail.com>
+    Copyright (C) 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
+
+    Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301  USA.
+*/
+
+#ifndef PTY_H
+#define PTY_H
+
+// Qt
+#include <QtCore/QStringList>
+#include <QtCore/QVector>
+#include <QtCore/QList>
+#include <QtCore>
+
+#include "k3process.h"
+
+
+namespace Konsole
+{
+
+/**
+ * The Pty class is used to start the terminal process, 
+ * send data to it, receive data from it and manipulate 
+ * various properties of the pseudo-teletype interface
+ * used to communicate with the process.
+ *
+ * To use this class, construct an instance and connect
+ * to the sendData slot and receivedData signal to
+ * send data to or receive data from the process.
+ *
+ * To start the terminal process, call the start() method
+ * with the program name and appropriate arguments. 
+ */
+class Pty: public K3Process
+{
+Q_OBJECT
+
+  public:
+    
+    /** 
+     * Constructs a new Pty.
+     * 
+     * Connect to the sendData() slot and receivedData() signal to prepare
+     * for sending and receiving data from the terminal process.
+     *
+     * To start the terminal process, call the run() method with the 
+     * name of the program to start and appropriate arguments.
+     */
+    Pty();
+    ~Pty();
+
+    /**
+     * Starts the terminal process.  
+     *
+     * Returns 0 if the process was started successfully or non-zero
+     * otherwise.
+     *
+     * @param program Path to the program to start
+     * @param arguments Arguments to pass to the program being started
+     * @param environment A list of key=value pairs which will be added
+     * to the environment for the new process.  At the very least this
+     * should include an assignment for the TERM environment variable.
+     * @param winid Specifies the value of the WINDOWID environment variable
+     * in the process's environment.
+     * @param addToUtmp Specifies whether a utmp entry should be created for
+     * the pty used.  See K3Process::setUsePty() 
+     * @param dbusService Specifies the value of the KONSOLE_DBUS_SERVICE 
+     * environment variable in the process's environment.
+     * @param dbusSession Specifies the value of the KONSOLE_DBUS_SESSION
+     * environment variable in the process's environment. 
+     */
+    int start( const QString& program, 
+               const QStringList& arguments, 
+               const QStringList& environment, 
+               ulong winid, 
+               bool addToUtmp
+//               const QString& dbusService,
+//               const QString& dbusSession
+             );
+
+    /** TODO: Document me */
+    void setWriteable(bool writeable);
+
+    /** 
+     * Enables or disables Xon/Xoff flow control.
+     */
+    void setXonXoff(bool on);
+
+    /** 
+     * Sets the size of the window (in lines and columns of characters) 
+     * used by this teletype.
+     */
+    void setWindowSize(int lines, int cols);
+    
+    /** Returns the size of the window used by this teletype.  See setWindowSize() */
+    QSize windowSize() const;
+
+    /** TODO Document me */
+    void setErase(char erase);
+
+	/** */
+	char erase() const;
+
+    /**
+     * Returns the process id of the teletype's current foreground
+     * process.  This is the process which is currently reading
+     * input sent to the terminal via. sendData()
+     *
+     * If there is a problem reading the foreground process group,
+     * 0 will be returned.
+     */
+    int foregroundProcessGroup() const;
+   
+    /**
+     * Returns whether the buffer used to send data to the
+     * terminal process is full.
+     */
+    bool bufferFull() const { return _bufferFull; }
+
+
+  public slots:
+
+    /**
+     * Put the pty into UTF-8 mode on systems which support it.
+     */
+    void setUtf8Mode(bool on);
+
+    /**
+     * Suspend or resume processing of data from the standard 
+     * output of the terminal process.
+     *
+     * See K3Process::suspend() and K3Process::resume()
+     *
+     * @param lock If true, processing of output is suspended,
+     * otherwise processing is resumed.
+     */
+    void lockPty(bool lock);
+    
+    /** 
+     * Sends data to the process currently controlling the 
+     * teletype ( whose id is returned by foregroundProcessGroup() )
+     *
+     * @param buffer Pointer to the data to send.
+     * @param length Length of @p buffer.
+     */
+    void sendData(const char* buffer, int length);
+
+  signals:
+
+    /**
+     * Emitted when the terminal process terminates.
+     *
+     * @param exitCode The status code which the process exited with.
+     */
+    void done(int exitCode);
+
+    /**
+     * Emitted when a new block of data is received from
+     * the teletype.
+     *
+     * @param buffer Pointer to the data received.
+     * @param length Length of @p buffer
+     */
+    void receivedData(const char* buffer, int length);
+    
+    /**
+     * Emitted when the buffer used to send data to the terminal
+     * process becomes empty, i.e. all data has been sent.
+     */
+    void bufferEmpty();
+    
+
+  private slots:
+    
+    // called when terminal process exits
+    void donePty();
+    // called when data is received from the terminal process 
+    void dataReceived(K3Process*, char* buffer, int length);
+    // sends the first enqueued buffer of data to the
+    // terminal process
+    void doSendJobs();
+    // called when the terminal process is ready to
+    // receive more data
+    void writeReady();
+
+  private:
+    // takes a list of key=value pairs and adds them
+    // to the environment for the process
+    void addEnvironmentVariables(const QStringList& environment);
+
+    // enqueues a buffer of data to be sent to the 
+    // terminal process
+    void appendSendJob(const char* buffer, int length);
+   
+    // a buffer of data in the queue to be sent to the 
+    // terminal process 
+    class SendJob {
+	public:
+      		SendJob() {}
+      		SendJob(const char* b, int len) : buffer(len)
+		{
+			memcpy( buffer.data() , b , len );
+        }
+	
+		const char* data() const { return buffer.constData(); }
+		int length() const { return buffer.size(); }	
+	private:
+      		QVector<char> buffer;
+    };
+
+    QList<SendJob> _pendingSendJobs;
+    bool _bufferFull;
+
+    int  _windowColumns; 
+    int  _windowLines;
+    char _eraseChar;
+    bool _xonXoff;
+    bool _utf8;
+    KPty *_pty;
+};
+
+}
+
+#endif // PTY_H
new file mode 100755
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..07caf7b0e3d6c22453226397d57eed57d2879394
GIT binary patch
literal 543012
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
new file mode 100644
--- /dev/null
+++ b/gui//Screen.cpp
@@ -0,0 +1,1567 @@
+/*
+    This file is part of Konsole, an X terminal.
+    Copyright (C) 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
+
+    Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301  USA.
+*/
+
+// Own
+#include "Screen.h"
+
+// Standard
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <assert.h>
+#include <string.h>
+#include <ctype.h>
+
+// Qt
+#include <QtCore/QTextStream>
+#include <QtCore/QDate>
+
+// Konsole
+#include "konsole_wcwidth.h"
+#include "TerminalCharacterDecoder.h"
+
+using namespace Konsole;
+
+//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
+
+//Macro to convert x,y position on screen to position within an image.
+//
+//Originally the image was stored as one large contiguous block of 
+//memory, so a position within the image could be represented as an
+//offset from the beginning of the block.  For efficiency reasons this
+//is no longer the case.  
+//Many internal parts of this class still use this representation for parameters and so on,
+//notably moveImage() and clearImage().
+//This macro converts from an X,Y position into an image offset.
+#ifndef loc
+#define loc(X,Y) ((Y)*columns+(X))
+#endif
+
+
+Character Screen::defaultChar = Character(' ',
+					  CharacterColor(COLOR_SPACE_DEFAULT,DEFAULT_FORE_COLOR),
+					  CharacterColor(COLOR_SPACE_DEFAULT,DEFAULT_BACK_COLOR),
+					  DEFAULT_RENDITION);
+
+//#define REVERSE_WRAPPED_LINES  // for wrapped line debug
+
+Screen::Screen(int l, int c)
+  : lines(l),
+    columns(c),
+    screenLines(new ImageLine[lines+1] ),
+    _scrolledLines(0),
+    _droppedLines(0),
+    hist(new HistoryScrollNone()),
+    cuX(0), cuY(0),
+    cu_re(0),
+    tmargin(0), bmargin(0),
+    tabstops(0),
+    sel_begin(0), sel_TL(0), sel_BR(0),
+    sel_busy(false),
+    columnmode(false),
+    ef_fg(CharacterColor()), ef_bg(CharacterColor()), ef_re(0),
+    sa_cuX(0), sa_cuY(0),
+    sa_cu_re(0),
+    lastPos(-1)
+{
+  lineProperties.resize(lines+1);
+  for (int i=0;i<lines+1;i++)
+          lineProperties[i]=LINE_DEFAULT;
+
+  initTabStops();
+  clearSelection();
+  reset();
+}
+
+/*! Destructor
+*/
+
+Screen::~Screen()
+{
+  delete[] screenLines;
+  delete[] tabstops;
+  delete hist;
+}
+
+/* ------------------------------------------------------------------------- */
+/*                                                                           */
+/* 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 Screen::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 Screen::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 Screen::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 Screen::cursorRight(int n)
+//=CUF
+{
+  if (n == 0) n = 1; // Default
+  cuX = qMin(columns-1,cuX+n);
+}
+
+void Screen::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 ) )
+  { qDebug()<<" setRegion("<<top<<","<<bot<<") : bad range.";
+    return;                   // Default error action: ignore
+  }
+  tmargin = top;
+  bmargin = bot;
+  cuX = 0;
+  cuY = getMode(MODE_Origin) ? top : 0;
+
+}
+
+int Screen::topMargin() const
+{
+    return tmargin;
+}
+int Screen::bottomMargin() const
+{
+    return bmargin;
+}
+
+void Screen::index()
+//=IND
+{
+  if (cuY == bmargin)
+  {
+    scrollUp(1);
+  }
+  else if (cuY < lines-1)
+    cuY += 1;
+}
+
+void Screen::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 Screen::NextLine()
+//=NEL
+{
+  Return(); index();
+}
+
+void Screen::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),' ');
+}
+
+void Screen::deleteChars(int n)
+{
+  Q_ASSERT( n >= 0 );
+
+  // always delete at least one char
+  if (n == 0) 
+      n = 1; 
+
+  // if cursor is beyond the end of the line there is nothing to do
+  if ( cuX >= screenLines[cuY].count() )
+      return;
+
+  if ( cuX+n >= screenLines[cuY].count() ) 
+       n = screenLines[cuY].count() - 1 - cuX;
+
+  Q_ASSERT( n >= 0 );
+  Q_ASSERT( cuX+n < screenLines[cuY].count() );
+
+  screenLines[cuY].remove(cuX,n);
+}
+
+void Screen::insertChars(int n)
+{
+  if (n == 0) n = 1; // Default
+
+  if ( screenLines[cuY].size() < cuX )
+    screenLines[cuY].resize(cuX);
+
+  screenLines[cuY].insert(cuX,n,' ');
+
+  if ( screenLines[cuY].count() > columns )
+      screenLines[cuY].resize(columns);
+}
+
+void Screen::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 Screen::insertLines(int n)
+{
+  if (n == 0) n = 1; // Default
+  scrollDown(cuY,n);
+}
+
+// Mode Operations -----------------------------------------------------------
+
+/*! Set a specific mode. */
+
+void Screen::setMode(int m)
+{
+  currParm.mode[m] = true;
+  switch(m)
+  {
+    case MODE_Origin : cuX = 0; cuY = tmargin; break; //FIXME: home
+  }
+}
+
+/*! Reset a specific mode. */
+
+void Screen::resetMode(int m)
+{
+  currParm.mode[m] = false;
+  switch(m)
+  {
+    case MODE_Origin : cuX = 0; cuY = 0; break; //FIXME: home
+  }
+}
+
+/*! Save a specific mode. */
+
+void Screen::saveMode(int m)
+{
+  saveParm.mode[m] = currParm.mode[m];
+}
+
+/*! Restore a specific mode. */
+
+void Screen::restoreMode(int m)
+{
+  currParm.mode[m] = saveParm.mode[m];
+}
+
+bool Screen::getMode(int m) const
+{
+  return currParm.mode[m];
+}
+
+void Screen::saveCursor()
+{
+  sa_cuX     = cuX;
+  sa_cuY     = cuY;
+  sa_cu_re   = cu_re;
+  sa_cu_fg   = cu_fg;
+  sa_cu_bg   = cu_bg;
+}
+
+void Screen::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                             */
+/*                                                                           */
+/* ------------------------------------------------------------------------- */
+
+/*! Resize the screen image
+
+    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.
+
+    If the new image is narrower than the old image then text on lines
+    which extends past the end of the new image is preserved so that it becomes
+    visible again if the screen is later resized to make it larger.
+*/
+
+void Screen::resizeImage(int new_lines, int new_columns)
+{
+  if ((new_lines==lines) && (new_columns==columns)) return;
+
+  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);
+    }
+  }
+
+  // create new screen lines and copy from old to new
+  
+   ImageLine* newScreenLines = new ImageLine[new_lines+1];
+   for (int i=0; i < qMin(lines-1,new_lines+1) ;i++)
+           newScreenLines[i]=screenLines[i];
+   for (int i=lines;(i > 0) && (i<new_lines+1);i++)
+           newScreenLines[i].resize( new_columns );
+   
+  lineProperties.resize(new_lines+1);
+  for (int i=lines;(i > 0) && (i<new_lines+1);i++)
+          lineProperties[i] = LINE_DEFAULT;
+
+  clearSelection();
+ 
+  delete[] screenLines; 
+  screenLines = newScreenLines;
+
+  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();
+}
+
+void Screen::setDefaultMargins()
+{
+	tmargin = 0;
+	bmargin = lines-1;
+}
+
+
+/*
+   Clarifying rendition here and in the display.
+
+   currently, the display'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 TerminalDisplay'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 Screen::reverseRendition(Character& p) const
+{ 
+	CharacterColor f = p.foregroundColor; 
+	CharacterColor b = p.backgroundColor;
+  	
+	p.foregroundColor = b; 
+	p.backgroundColor = f; //p->r &= ~RE_TRANSPARENT;
+}
+
+void Screen::effectiveRendition()
+// calculate rendition
+{
+  //copy "current rendition" straight into "effective rendition", which is then later copied directly
+  //into the image[] array which holds the characters and their appearance properties.
+  //- The old version below filtered out all attributes other than underline and blink at this stage,
+  //so that they would not be copied into the image[] array and hence would not be visible by TerminalDisplay
+  //which actually paints the screen using the information from the image[] array.  
+  //I don't know why it did this, but I'm fairly sure it was the wrong thing to do.  The net result
+  //was that bold text wasn't printed in bold by Konsole.
+  ef_re = cu_re;
+  
+  //OLD VERSION:
+  //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)
+    ef_fg.toggleIntensive();
+}
+
+/*!
+    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.
+
+*/
+
+void Screen::copyFromHistory(Character* dest, int startLine, int count) const
+{
+  Q_ASSERT( startLine >= 0 && count > 0 && startLine + count <= hist->getLines() );
+
+  for (int line = startLine; line < startLine + count; line++) 
+  {
+    const int length = qMin(columns,hist->getLineLen(line));
+    const int destLineOffset  = (line-startLine)*columns;
+
+    hist->getCells(line,0,length,dest + destLineOffset);
+
+    for (int column = length; column < columns; column++) 
+		dest[destLineOffset+column] = defaultChar;
+    
+	// invert selected text
+	if (sel_begin !=-1)
+	{
+    	for (int column = 0; column < columns; column++)
+    	{
+        	if (isSelected(column,line)) 
+			{
+          		reverseRendition(dest[destLineOffset + column]); 
+    		}
+  		}
+	}
+  }
+}
+
+void Screen::copyFromScreen(Character* dest , int startLine , int count) const
+{
+	Q_ASSERT( startLine >= 0 && count > 0 && startLine + count <= lines );
+
+    for (int line = startLine; line < (startLine+count) ; line++)
+    {
+       int srcLineStartIndex  = line*columns;
+	   int destLineStartIndex = (line-startLine)*columns;
+
+       for (int column = 0; column < columns; column++)
+       { 
+		 int srcIndex = srcLineStartIndex + column; 
+		 int destIndex = destLineStartIndex + column;
+
+         dest[destIndex] = screenLines[srcIndex/columns].value(srcIndex%columns,defaultChar);
+
+	     // invert selected text
+         if (sel_begin != -1 && isSelected(column,line + hist->getLines()))
+           reverseRendition(dest[destIndex]); 
+       }
+
+    }
+}
+
+void Screen::getImage( Character* dest, int size, int startLine, int endLine ) const
+{
+  Q_ASSERT( startLine >= 0 ); 
+  Q_ASSERT( endLine >= startLine && endLine < hist->getLines() + lines );
+
+  const int mergedLines = endLine - startLine + 1;
+
+  Q_ASSERT( size >= mergedLines * columns ); 
+
+  const int linesInHistoryBuffer = qBound(0,hist->getLines()-startLine,mergedLines);
+  const int linesInScreenBuffer = mergedLines - linesInHistoryBuffer;
+
+  // copy lines from history buffer
+  if (linesInHistoryBuffer > 0) {
+  	copyFromHistory(dest,startLine,linesInHistoryBuffer); 
+    }
+
+  // copy lines from screen buffer
+  if (linesInScreenBuffer > 0) {
+  	copyFromScreen(dest + linesInHistoryBuffer*columns,
+				   startLine + linesInHistoryBuffer - hist->getLines(),
+				   linesInScreenBuffer);
+    }				
+ 
+  // invert display when in screen mode
+  if (getMode(MODE_Screen))
+  {  
+    for (int i = 0; i < mergedLines*columns; i++)
+      reverseRendition(dest[i]); // for reverse display
+  }
+
+  // mark the character at the current cursor position
+  int cursorIndex = loc(cuX, cuY + linesInHistoryBuffer);
+  if(getMode(MODE_Cursor) && cursorIndex < columns*mergedLines)
+    dest[cursorIndex].rendition |= RE_CURSOR;
+}
+
+QVector<LineProperty> Screen::getLineProperties( int startLine , int endLine ) const
+{
+  Q_ASSERT( startLine >= 0 ); 
+  Q_ASSERT( endLine >= startLine && endLine < hist->getLines() + lines );
+
+	const int mergedLines = endLine-startLine+1;
+	const int linesInHistory = qBound(0,hist->getLines()-startLine,mergedLines);
+  const int linesInScreen = mergedLines - linesInHistory;
+
+  QVector<LineProperty> result(mergedLines);
+  int index = 0;
+
+  // copy properties for lines in history
+  for (int line = startLine; line < startLine + linesInHistory; line++) 
+  {
+		//TODO Support for line properties other than wrapped lines
+	  if (hist->isWrappedLine(line))
+	  {
+	  	result[index] = (LineProperty)(result[index] | LINE_WRAPPED);
+	  }
+    index++;
+  }
+  
+  // copy properties for lines in screen buffer
+  const int firstScreenLine = startLine + linesInHistory - hist->getLines();
+  for (int line = firstScreenLine; line < firstScreenLine+linesInScreen; line++)
+	{
+    result[index]=lineProperties[line];
+  	index++;
+	}
+
+  return result;
+}
+
+/*!
+*/
+
+void Screen::reset(bool clearScreen)
+{
+    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();
+
+  if ( clearScreen )
+    clear();
+}
+
+/*! Clear the entire screen and home the cursor.
+*/
+
+void Screen::clear()
+{
+  clearEntireScreen();
+  home();
+}
+
+void Screen::BackSpace()
+{
+  cuX = qMin(columns-1,cuX); // nowrap!
+  cuX = qMax(0,cuX-1);
+ // if (BS_CLEARS) image[loc(cuX,cuY)].character = ' ';
+
+  if (screenLines[cuY].size() < cuX+1)
+          screenLines[cuY].resize(cuX+1);
+
+  if (BS_CLEARS) screenLines[cuY][cuX].character = ' ';
+}
+
+void Screen::Tabulate(int n)
+{
+  // note that TAB is a format effector (does not write ' ');
+  if (n == 0) n = 1;
+  while((n > 0) && (cuX < columns-1))
+  {
+    cursorRight(1); while((cuX < columns-1) && !tabstops[cuX]) cursorRight(1);
+    n--;
+  }
+}
+
+void Screen::backTabulate(int n)
+{
+  // note that TAB is a format effector (does not write ' ');
+  if (n == 0) n = 1;
+  while((n > 0) && (cuX > 0))
+  {
+     cursorLeft(1); while((cuX > 0) && !tabstops[cuX]) cursorLeft(1);
+     n--;
+  }
+}
+
+void Screen::clearTabStops()
+{
+  for (int i = 0; i < columns; i++) tabstops[i] = false;
+}
+
+void Screen::changeTabStop(bool set)
+{
+  if (cuX >= columns) return;
+  tabstops[cuX] = set;
+}
+
+void Screen::initTabStops()
+{
+  delete[] tabstops;
+  tabstops = new bool[columns];
+
+  // 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 Screen::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 Screen::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 Screen::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.
+
+  int w = konsole_wcwidth(c);
+
+  if (w <= 0)
+     return;
+
+  if (cuX+w > columns) {
+    if (getMode(MODE_Wrap)) {
+      lineProperties[cuY] = (LineProperty)(lineProperties[cuY] | LINE_WRAPPED);
+      NextLine();
+    }
+    else
+      cuX = columns-w;
+  }
+
+  // ensure current line vector has enough elements
+  int size = screenLines[cuY].size();
+  if (size == 0 && cuY > 0)
+  {
+          screenLines[cuY].resize( qMax(screenLines[cuY-1].size() , cuX+w) );
+  }
+  else
+  {
+    if (size < cuX+w)
+    {
+          screenLines[cuY].resize(cuX+w);
+    }
+  }
+
+  if (getMode(MODE_Insert)) insertChars(w);
+
+  lastPos = loc(cuX,cuY);
+
+  // check if selection is still valid.
+  checkSelection(cuX,cuY);
+
+  Character& currentChar = screenLines[cuY][cuX];
+
+  currentChar.character = c;
+  currentChar.foregroundColor = ef_fg;
+  currentChar.backgroundColor = ef_bg;
+  currentChar.rendition = ef_re;
+
+  int i = 0;
+  int newCursorX = cuX + w--;
+  while(w)
+  {
+     i++;
+   
+     if ( screenLines[cuY].size() < cuX + i + 1 )
+         screenLines[cuY].resize(cuX+i+1);
+     
+     Character& ch = screenLines[cuY][cuX + i];
+     ch.character = 0;
+     ch.foregroundColor = ef_fg;
+     ch.backgroundColor = ef_bg;
+     ch.rendition = ef_re;
+
+     w--;
+  }
+  cuX = newCursorX;
+}
+
+void Screen::compose(const QString& /*compose*/)
+{
+   Q_ASSERT( 0 /*Not implemented yet*/ );
+
+/*  if (lastPos == -1)
+     return;
+     
+  QChar c(image[lastPos].character);
+  compose.prepend(c);
+  //compose.compose(); ### FIXME!
+  image[lastPos].character = compose[0].unicode();*/
+}
+
+int Screen::scrolledLines() const
+{
+        return _scrolledLines;
+}
+int Screen::droppedLines() const
+{
+    return _droppedLines;
+}
+void Screen::resetDroppedLines()
+{
+    _droppedLines = 0;
+}
+void Screen::resetScrolledLines()
+{
+    //kDebug() << "scrolled lines reset";
+
+    _scrolledLines = 0;
+}
+
+// Region commands -------------------------------------------------------------
+
+void Screen::scrollUp(int n)
+{
+   if (n == 0) n = 1; // Default
+   if (tmargin == 0) addHistLine(); // hist.history
+   scrollUp(tmargin, n);
+}
+
+/*! scroll up `n' lines within current region.
+    The `n' new lines are cleared.
+    \sa setRegion \sa scrollDown
+*/
+
+QRect Screen::lastScrolledRegion() const
+{
+    return _lastScrolledRegion;
+}
+
+void Screen::scrollUp(int from, int n)
+{
+  if (n <= 0 || from + n > bmargin) return;
+
+  _scrolledLines -= n;
+  _lastScrolledRegion = QRect(0,tmargin,columns-1,(bmargin-tmargin));
+
+  //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),' ');
+}
+
+void Screen::scrollDown(int n)
+{
+   if (n == 0) n = 1; // Default
+   scrollDown(tmargin, n);
+}
+
+/*! scroll down `n' lines within current region.
+    The `n' new lines are cleared.
+    \sa setRegion \sa scrollUp
+*/
+
+void Screen::scrollDown(int from, int n)
+{
+
+  //kDebug() << "Screen::scrollDown( from: " << from << " , n: " << n << ")";
+  
+  _scrolledLines += 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),' ');
+}
+
+void Screen::setCursorYX(int y, int x)
+{
+  setCursorY(y); setCursorX(x);
+}
+
+void Screen::setCursorX(int x)
+{
+  if (x == 0) x = 1; // Default
+  x -= 1; // Adjust
+  cuX = qMax(0,qMin(columns-1, x));
+}
+
+void Screen::setCursorY(int y)
+{
+  if (y == 0) y = 1; // Default
+  y -= 1; // Adjust
+  cuY = qMax(0,qMin(lines  -1, y + (getMode(MODE_Origin) ? tmargin : 0) ));
+}
+
+void Screen::home()
+{
+  cuX = 0;
+  cuY = 0;
+}
+
+void Screen::Return()
+{
+  cuX = 0;
+}
+
+int Screen::getCursorX() const
+{
+  return cuX;
+}
+
+int Screen::getCursorY() const
+{
+  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' (start) and `loce' (end) 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 Screen::clearImage(int loca, int loce, char c)
+{ 
+  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();
+  }
+
+  int topLine = loca/columns;
+  int bottomLine = loce/columns;
+
+  Character clearCh(c,cu_fg,cu_bg,DEFAULT_RENDITION);
+  
+  //if the character being used to clear the area is the same as the
+  //default character, the affected lines can simply be shrunk.
+  bool isDefaultCh = (clearCh == Character());
+
+  for (int y=topLine;y<=bottomLine;y++)
+  {
+        lineProperties[y] = 0;
+
+        int endCol = ( y == bottomLine) ? loce%columns : columns-1;
+        int startCol = ( y == topLine ) ? loca%columns : 0;
+
+        QVector<Character>& line = screenLines[y];
+
+        if ( isDefaultCh && endCol == columns-1 )
+        {
+            line.resize(startCol);
+        }
+        else
+        {
+            if (line.size() < endCol + 1)
+                line.resize(endCol+1);
+
+            Character* data = line.data();
+            for (int i=startCol;i<=endCol;i++)
+                data[i]=clearCh;
+        }
+  }
+}
+
+/*! move image between (including) `sourceBegin' and `sourceEnd' to 'dest'.
+    
+    The 'dest', 'sourceBegin' and 'sourceEnd' parameters can be generated using
+    the loc(column,line) macro.
+
+NOTE:  moveImage() can only move whole lines.
+
+    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 Screen::moveImage(int dest, int sourceBegin, int sourceEnd)
+{
+  //kDebug() << "moving image from (" << (sourceBegin/columns) 
+  //    << "," << (sourceEnd/columns) << ") to " <<
+  //    (dest/columns);
+
+  Q_ASSERT( sourceBegin <= sourceEnd );
+ 
+  int lines=(sourceEnd-sourceBegin)/columns;
+
+  //move screen image and line properties:
+  //the source and destination areas of the image may overlap, 
+  //so it matters that we do the copy in the right order - 
+  //forwards if dest < sourceBegin or backwards otherwise.
+  //(search the web for 'memmove implementation' for details)
+  if (dest < sourceBegin)
+  {
+    for (int i=0;i<=lines;i++)
+    {
+        screenLines[ (dest/columns)+i ] = screenLines[ (sourceBegin/columns)+i ];
+        lineProperties[(dest/columns)+i]=lineProperties[(sourceBegin/columns)+i];
+    }
+  }
+  else
+  {
+    for (int i=lines;i>=0;i--)
+    {
+        screenLines[ (dest/columns)+i ] = screenLines[ (sourceBegin/columns)+i ];
+        lineProperties[(dest/columns)+i]=lineProperties[(sourceBegin/columns)+i];
+    }
+  }
+
+  if (lastPos != -1)
+  {
+     int diff = dest - sourceBegin; // Scroll by this amount
+     lastPos += diff;
+     if ((lastPos < 0) || (lastPos >= (lines*columns)))
+        lastPos = -1;
+  }
+     
+  // Adjust selection to follow scroll.
+  if (sel_begin != -1)
+  {
+     bool beginIsTL = (sel_begin == sel_TL);
+     int diff = dest - sourceBegin; // Scroll by this amount
+     int scr_TL=loc(0,hist->getLines());
+     int srca = sourceBegin+scr_TL; // Translate index from screen to global
+     int srce = sourceEnd+scr_TL; // Translate index from screen to global
+     int desta = srca+diff;
+     int deste = srce+diff;
+
+     if ((sel_TL >= srca) && (sel_TL <= srce))
+        sel_TL += diff;
+     else if ((sel_TL >= desta) && (sel_TL <= deste))
+        sel_BR = -1; // Clear selection (see below)
+
+     if ((sel_BR >= srca) && (sel_BR <= srce))
+        sel_BR += diff;
+     else if ((sel_BR >= desta) && (sel_BR <= deste))
+        sel_BR = -1; // Clear selection (see below)
+
+     if (sel_BR < 0)
+     {
+        clearSelection();
+     }
+     else
+     {
+        if (sel_TL < 0)
+           sel_TL = 0;
+     }
+
+     if (beginIsTL)
+        sel_begin = sel_TL;
+     else
+        sel_begin = sel_BR;
+  }
+}
+
+void Screen::clearToEndOfScreen()
+{
+  clearImage(loc(cuX,cuY),loc(columns-1,lines-1),' ');
+}
+
+void Screen::clearToBeginOfScreen()
+{
+  clearImage(loc(0,0),loc(cuX,cuY),' ');
+}
+
+void Screen::clearEntireScreen()
+{
+  // Add entire screen to history
+  for (int i = 0; i < (lines-1); i++)
+  {
+    addHistLine(); scrollUp(0,1);
+  }
+
+  clearImage(loc(0,0),loc(columns-1,lines-1),' ');
+}
+
+/*! fill screen with 'E'
+    This is to aid screen alignment
+*/
+
+void Screen::helpAlign()
+{
+  clearImage(loc(0,0),loc(columns-1,lines-1),'E');
+}
+
+void Screen::clearToEndOfLine()
+{
+  clearImage(loc(cuX,cuY),loc(columns-1,cuY),' ');
+}
+
+void Screen::clearToBeginOfLine()
+{
+  clearImage(loc(0,cuY),loc(cuX,cuY),' ');
+}
+
+void Screen::clearEntireLine()
+{
+  clearImage(loc(0,cuY),loc(columns-1,cuY),' ');
+}
+
+void Screen::setRendition(int re)
+{
+  cu_re |= re;
+  effectiveRendition();
+}
+
+void Screen::resetRendition(int re)
+{
+  cu_re &= ~re;
+  effectiveRendition();
+}
+
+void Screen::setDefaultRendition()
+{
+  setForeColor(COLOR_SPACE_DEFAULT,DEFAULT_FORE_COLOR);
+  setBackColor(COLOR_SPACE_DEFAULT,DEFAULT_BACK_COLOR);
+  cu_re   = DEFAULT_RENDITION;
+  effectiveRendition();
+}
+
+void Screen::setForeColor(int space, int color)
+{
+  cu_fg = CharacterColor(space, color);
+
+  if ( cu_fg.isValid() ) 
+    effectiveRendition();
+  else 
+    setForeColor(COLOR_SPACE_DEFAULT,DEFAULT_FORE_COLOR);
+}
+
+void Screen::setBackColor(int space, int color)
+{
+  cu_bg = CharacterColor(space, color);
+
+  if ( cu_bg.isValid() ) 
+    effectiveRendition();
+  else
+    setBackColor(COLOR_SPACE_DEFAULT,DEFAULT_BACK_COLOR);
+}
+
+/* ------------------------------------------------------------------------- */
+/*                                                                           */
+/*                            Marking & Selection                            */
+/*                                                                           */
+/* ------------------------------------------------------------------------- */
+
+void Screen::clearSelection()
+{
+  sel_BR = -1;
+  sel_TL = -1;
+  sel_begin = -1;
+}
+
+void Screen::getSelectionStart(int& column , int& line)
+{
+    if ( sel_TL != -1 )
+    {
+        column = sel_TL % columns;
+        line = sel_TL / columns; 
+    }
+    else
+    {
+        column = cuX + getHistLines();
+        line = cuY + getHistLines();
+    }
+}
+void Screen::getSelectionEnd(int& column , int& line)
+{
+    if ( sel_BR != -1 )
+    {
+        column = sel_BR % columns;
+        line = sel_BR / columns;
+    }
+    else
+    {
+        column = cuX + getHistLines();
+        line = cuY + getHistLines();
+    } 
+}
+void Screen::setSelectionStart(/*const ScreenCursor& viewCursor ,*/ const int x, const int y, const bool mode)
+{
+//  kDebug(1211) << "setSelBeginXY(" << x << "," << y << ")";
+  sel_begin = loc(x,y); //+histCursor) ;
+
+  /* FIXME, HACK to correct for x too far to the right... */
+  if (x == columns) sel_begin--;
+
+  sel_BR = sel_begin;
+  sel_TL = sel_begin;
+  columnmode = mode;
+}
+
+void Screen::setSelectionEnd( const int x, const int y)
+{
+//  kDebug(1211) << "setSelExtentXY(" << x << "," << 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) l--;
+
+    sel_TL = sel_begin;
+    sel_BR = l;
+  }
+}
+
+bool Screen::isSelected( const int x,const int y) const
+{
+  if (columnmode) {
+    int sel_Left,sel_Right;
+    if ( sel_TL % columns < sel_BR % columns ) {
+      sel_Left = sel_TL; sel_Right = sel_BR;
+    } else {
+      sel_Left = sel_BR; sel_Right = sel_TL;
+    }
+    return ( x >= sel_Left % columns ) && ( x <= sel_Right % columns ) &&
+           ( y >= sel_TL / columns ) && ( y <= sel_BR / columns );
+            //( y+histCursor >= sel_TL / columns ) && ( y+histCursor <= sel_BR / columns );
+  }
+  else {
+  //int pos = loc(x,y+histCursor);
+  int pos = loc(x,y);
+  return ( pos >= sel_TL && pos <= sel_BR );
+  }
+}
+
+QString Screen::selectedText(bool preserveLineBreaks)
+{
+  QString result;
+  QTextStream stream(&result, QIODevice::ReadWrite);
+  
+  PlainTextDecoder decoder;
+  decoder.begin(&stream);
+  writeSelectionToStream(&decoder , preserveLineBreaks);
+  decoder.end();
+  
+  return result;
+}
+
+bool Screen::isSelectionValid() const
+{
+    return ( sel_TL >= 0 && sel_BR >= 0 );
+}
+
+void Screen::writeSelectionToStream(TerminalCharacterDecoder* decoder , 
+                                    bool preserveLineBreaks)
+{
+    // do nothing if selection is invalid
+    if ( !isSelectionValid() )
+        return;
+
+	int top = sel_TL / columns;	
+	int left = sel_TL % columns;
+
+	int bottom = sel_BR / columns;
+	int right = sel_BR % columns;
+
+    Q_ASSERT( top >= 0 && left >= 0 && bottom >= 0 && right >= 0 );
+
+    //kDebug() << "sel_TL = " << sel_TL;
+    //kDebug() << "columns = " << columns;
+
+	for (int y=top;y<=bottom;y++)
+	{
+			int start = 0;
+			if ( y == top || columnmode ) start = left;
+		
+			int count = -1;
+			if ( y == bottom || columnmode ) count = right - start + 1;
+
+            const bool appendNewLine = ( y != bottom );
+			copyLineToStream( y,
+                              start,
+                              count,
+                              decoder, 
+                              appendNewLine,
+                              preserveLineBreaks );
+	}	
+}
+
+
+void Screen::copyLineToStream(int line , 
+                              int start, 
+                              int count,
+                              TerminalCharacterDecoder* decoder,
+                              bool appendNewLine,
+                              bool preserveLineBreaks)
+{
+		//buffer to hold characters for decoding
+		//the buffer is static to avoid initialising every 
+        //element on each call to copyLineToStream
+		//(which is unnecessary since all elements will be overwritten anyway)
+		static const int MAX_CHARS = 1024;
+		static Character characterBuffer[MAX_CHARS];
+		
+		assert( count < MAX_CHARS );
+
+        LineProperty currentLineProperties = 0;
+
+		//determine if the line is in the history buffer or the screen image
+		if (line < hist->getLines())
+		{
+            const int lineLength = hist->getLineLen(line);
+
+            // ensure that start position is before end of line
+            start = qMin(start,qMax(0,lineLength-1));
+
+			//retrieve line from history buffer
+			if (count == -1)
+            {
+					count = lineLength-start;
+            }
+			else
+            {
+					count = qMin(start+count,lineLength)-start;
+            }
+
+            // safety checks
+            assert( start >= 0 );
+            assert( count >= 0 );    
+            assert( (start+count) <= hist->getLineLen(line) );
+
+			hist->getCells(line,start,count,characterBuffer);
+
+            if ( hist->isWrappedLine(line) )
+                currentLineProperties |= LINE_WRAPPED;
+		}
+		else
+		{
+			if ( count == -1 )
+					count = columns - start;
+
+            assert( count >= 0 );
+
+            const int screenLine = line-hist->getLines();
+
+            Character* data = screenLines[screenLine].data();
+            int length = screenLines[screenLine].count();
+
+			//retrieve line from screen image
+			for (int i=start;i < qMin(start+count,length);i++)
+			{
+			    characterBuffer[i-start] = data[i];
+            }
+
+            // count cannot be any greater than length
+			count = qBound(0,count,length-start);
+
+            Q_ASSERT( screenLine < lineProperties.count() );
+            currentLineProperties |= lineProperties[screenLine]; 
+		}
+
+		//do not decode trailing whitespace characters
+		for (int i=count-1 ; i >= 0; i--)
+				if (QChar(characterBuffer[i].character).isSpace())
+						count--;
+				else
+						break;
+
+        // add new line character at end
+        const bool omitLineBreak = (currentLineProperties & LINE_WRAPPED) ||
+                                   !preserveLineBreaks;
+
+        if ( !omitLineBreak && appendNewLine && (count+1 < MAX_CHARS) )
+        {
+            characterBuffer[count] = '\n';
+            count++;
+        }
+
+		//decode line and write to text stream	
+		decoder->decodeLine( (Character*) characterBuffer , 
+                             count, currentLineProperties );
+}
+
+// Method below has been removed because of its reliance on 'histCursor'
+// and I want to restrict the methods which have knowledge of the scroll position
+// to just those which deal with selection and supplying final screen images.
+//
+/*void Screen::writeToStream(QTextStream* stream , TerminalCharacterDecoder* decoder) {
+  sel_begin = 0;
+  sel_BR = sel_begin;
+  sel_TL = sel_begin;
+  setSelectionEnd(columns-1,lines-1+hist->getLines()-histCursor);
+  
+  writeSelectionToStream(stream,decoder);
+  
+  clearSelection();
+}*/
+
+void Screen::writeToStream(TerminalCharacterDecoder* decoder, int from, int to)
+{
+	sel_begin = loc(0,from);
+	sel_TL = sel_begin;
+	sel_BR = loc(columns-1,to);
+	writeSelectionToStream(decoder);
+	clearSelection();
+}
+
+QString Screen::getHistoryLine(int no)
+{
+  sel_begin = loc(0,no);
+  sel_TL = sel_begin;
+  sel_BR = loc(columns-1,no);
+  return selectedText(false);
+}
+
+void Screen::addHistLine()
+{
+  // add line to history buffer
+  // we have to take care about scrolling, too...
+
+  if (hasScroll())
+  {
+    int oldHistLines = hist->getLines();
+
+    hist->addCellsVector(screenLines[0]);
+    hist->addLine( lineProperties[0] & LINE_WRAPPED );
+
+    int newHistLines = hist->getLines();
+
+    bool beginIsTL = (sel_begin == sel_TL);
+
+    // If the history is full, increment the count
+    // of dropped lines
+    if ( newHistLines == oldHistLines )
+        _droppedLines++;
+
+    // Adjust selection for the new point of reference
+    if (newHistLines > oldHistLines)
+    {
+       if (sel_begin != -1)
+       {
+          sel_TL += columns;
+          sel_BR += columns;
+       }
+    }
+
+    if (sel_begin != -1)
+    {
+       // Scroll selection in history up
+       int top_BR = loc(0, 1+newHistLines);
+
+       if (sel_TL < top_BR)
+          sel_TL -= columns;
+
+       if (sel_BR < top_BR)
+          sel_BR -= columns;
+
+       if (sel_BR < 0)
+       {
+          clearSelection();
+       }
+       else
+       {
+          if (sel_TL < 0)
+             sel_TL = 0;
+       }
+
+       if (beginIsTL)
+          sel_begin = sel_TL;
+       else
+          sel_begin = sel_BR;
+    }
+  }
+
+}
+
+int Screen::getHistLines()
+{
+  return hist->getLines();
+}
+
+void Screen::setScroll(const HistoryType& t , bool copyPreviousScroll)
+{
+  clearSelection();
+
+  if ( copyPreviousScroll )
+    hist = t.scroll(hist);
+  else
+  {
+      HistoryScroll* oldScroll = hist;
+      hist = t.scroll(0);
+      delete oldScroll;
+  }
+}
+
+bool Screen::hasScroll()
+{
+  return hist->hasScroll();
+}
+
+const HistoryType& Screen::getScroll()
+{
+  return hist->getType();
+}
+
+void Screen::setLineProperty(LineProperty property , bool enable)
+{
+	if ( enable )
+	{
+		lineProperties[cuY] = (LineProperty)(lineProperties[cuY] | property);
+	}
+	else
+	{
+		lineProperties[cuY] = (LineProperty)(lineProperties[cuY] & ~property);
+	}
+}
+void Screen::fillWithDefaultChar(Character* dest, int count)
+{
+	for (int i=0;i<count;i++)
+		dest[i] = defaultChar;
+}
new file mode 100644
--- /dev/null
+++ b/gui//Screen.h
@@ -0,0 +1,662 @@
+/*
+    This file is part of Konsole, KDE's terminal.
+
+    Copyright (C) 2007 by Robert Knight <robertknight@gmail.com>
+    Copyright (C) 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
+
+    Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301  USA.
+*/
+
+#ifndef SCREEN_H
+#define SCREEN_H
+
+// Qt
+#include <QtCore/QRect>
+#include <QtCore/QTextStream>
+#include <QtCore/QVarLengthArray>
+
+// Konsole
+#include "Character.h"
+#include "History.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
+
+namespace Konsole
+{
+
+/*!
+*/
+struct ScreenParm
+{
+  int mode[MODES_SCREEN];
+};
+
+class TerminalCharacterDecoder;
+
+/**
+    \brief An image of characters with associated attributes.
+
+    The terminal emulation ( Emulation ) receives a serial stream of
+    characters from the program currently running in the terminal.
+    From this stream it creates an image of characters which is ultimately
+    rendered by the display widget ( TerminalDisplay ).  Some types of emulation
+    may have more than one screen image. 
+
+    getImage() is used to retrieve the currently visible image
+    which is then used by the display widget to draw the output from the
+    terminal. 
+
+    The number of lines of output history which are kept in addition to the current
+    screen image depends on the history scroll being used to store the output.  
+    The scroll is specified using setScroll()
+    The output history can be retrieved using writeToStream()
+
+    The screen image has a selection associated with it, specified using 
+    setSelectionStart() and setSelectionEnd().  The selected text can be retrieved
+    using selectedText().  When getImage() is used to retrieve the the visible image,
+    characters which are part of the selection have their colours inverted.   
+*/
+class Screen
+{
+public:
+    /** Construct a new screen image of size @p lines by @p columns. */
+    Screen(int lines, int columns);
+    ~Screen();
+
+    // VT100/2 Operations 
+    // Cursor Movement
+    
+    /** Move the cursor up by @p n lines. */
+    void cursorUp    (int n);
+    /** Move the cursor down by @p n lines. */
+    void cursorDown  (int n);
+    /** Move the cursor to the left by @p n columns. */
+    void cursorLeft  (int n);
+    /** Move the cursor to the right by @p n columns. */
+    void cursorRight (int n);
+    /** Position the cursor on line @p y. */
+    void setCursorY  (int y);
+    /** Position the cursor at column @p x. */
+    void setCursorX  (int x);
+    /** Position the cursor at line @p y, column @p x. */
+    void setCursorYX (int y, int x);
+    /**
+     * Sets the margins for scrolling the screen.
+     *
+     * @param topLine The top line of the new scrolling margin. 
+     * @param bottomLine The bottom line of the new scrolling margin. 
+     */
+    void setMargins  (int topLine , int bottomLine);
+    /** Returns the top line of the scrolling region. */ 
+    int topMargin() const;
+    /** Returns the bottom line of the scrolling region. */
+    int bottomMargin() const;
+
+    /** 
+     * Resets the scrolling margins back to the top and bottom lines
+     * of the screen.
+     */
+    void setDefaultMargins();
+    
+    /** 
+     * Moves the cursor down one line, if the MODE_NewLine mode 
+     * flag is enabled then the cursor is returned to the leftmost
+     * column first.
+     *
+     * Equivalent to NextLine() if the MODE_NewLine flag is set
+     * or index() otherwise. 
+     */
+    void NewLine     ();
+    /**
+     * Moves the cursor down one line and positions it at the beginning
+     * of the line.
+     */
+    void NextLine    ();
+
+    /** 
+     * Move the cursor down one line.  If the cursor is on the bottom
+     * line of the scrolling region (as returned by bottomMargin()) the
+     * scrolling region is scrolled up by one line instead.
+     */
+    void index       ();
+    /**
+     * Move the cursor up one line.  If the cursor is on the top line
+     * of the scrolling region (as returned by topMargin()) the scrolling
+     * region is scrolled down by one line instead.
+     */
+    void reverseIndex();
+    
+    /** 
+     * Scroll the scrolling region of the screen up by @p n lines. 
+     * The scrolling region is initially the whole screen, but can be changed 
+     * using setMargins()
+     */ 
+    void scrollUp(int n);
+    /**
+     * Scroll the scrolling region of the screen down by @p n lines.
+     * The scrolling region is initially the whole screen, but can be changed
+     * using setMargins()
+     */
+    void scrollDown(int n);
+    
+    /** 
+     * Moves the cursor to the beginning of the current line. 
+     * Equivalent to setCursorX(0)
+     */
+    void Return      ();
+    /** 
+     * Moves the cursor one column to the left and erases the character
+     * at the new cursor position.
+     */
+    void BackSpace   ();
+    /** 
+     * Moves the cursor @p n tab-stops to the right.
+     */
+    void Tabulate    (int n = 1);
+    /** 
+     * Moves the cursor @p n tab-stops to the left. 
+     */
+    void backTabulate(int n);
+    
+    // Editing
+    
+    /** 
+     * Erase @p n characters beginning from the current cursor position. 
+     * This is equivalent to over-writing @p n characters starting with the current
+     * cursor position with spaces.
+     * If @p n is 0 then one character is erased. 
+     */
+    void eraseChars  (int n);
+    /** 
+     * Delete @p n characters beginning from the current cursor position. 
+     * If @p n is 0 then one character is deleted. 
+     */
+    void deleteChars (int n);
+    /**
+     * Insert @p n blank characters beginning from the current cursor position.
+     * The position of the cursor is not altered.  
+     * If @p n is 0 then one character is inserted.
+     */
+    void insertChars (int n);
+    /** 
+     * Removes @p n lines beginning from the current cursor position.
+     * The position of the cursor is not altered.
+     * If @p n is 0 then one line is removed.
+     */
+    void deleteLines (int n);
+    /**
+     * Inserts @p lines beginning from the current cursor position.
+     * The position of the cursor is not altered.
+     * If @p n is 0 then one line is inserted.
+     */
+    void insertLines (int n);
+    /** Clears all the tab stops. */
+    void clearTabStops();
+    /**  Sets or removes a tab stop at the cursor's current column. */ 
+    void changeTabStop(bool set);
+   
+    /** Resets (clears) the specified screen @p mode. */
+    void resetMode   (int mode);
+    /** Sets (enables) the specified screen @p mode. */
+    void setMode     (int mode);
+    /** 
+     * Saves the state of the specified screen @p mode.  It can be restored
+     * using restoreMode()
+     */
+    void saveMode    (int mode);
+    /** Restores the state of a screen @p mode saved by calling saveMode() */
+    void restoreMode (int mode);
+    /** Returns whether the specified screen @p mode is enabled or not .*/
+    bool getMode     (int mode) const;
+   
+    /** 
+     * Saves the current position and appearence (text color and style) of the cursor. 
+     * It can be restored by calling restoreCursor() 
+     */ 
+    void saveCursor  ();
+    /** Restores the position and appearence of the cursor.  See saveCursor() */
+    void restoreCursor();
+   
+    /** Clear the whole screen, moving the current screen contents into the history first. */ 
+    void clearEntireScreen();
+    /** 
+     * Clear the area of the screen from the current cursor position to the end of 
+     * the screen.
+     */
+    void clearToEndOfScreen();
+    /**
+     * Clear the area of the screen from the current cursor position to the start
+     * of the screen.
+     */
+    void clearToBeginOfScreen();
+    /** Clears the whole of the line on which the cursor is currently positioned. */
+    void clearEntireLine();
+    /** Clears from the current cursor position to the end of the line. */
+    void clearToEndOfLine();
+    /** Clears from the current cursor position to the beginning of the line. */
+    void clearToBeginOfLine();
+    
+    /** Fills the entire screen with the letter 'E' */
+    void helpAlign   ();
+       
+    /** 
+     * Enables the given @p rendition flag.  Rendition flags control the appearence 
+     * of characters on the screen.
+     *
+     * @see Character::rendition
+     */  
+    void setRendition  (int rendition);
+    /**
+     * Disables the given @p rendition flag.  Rendition flags control the appearence
+     * of characters on the screen.
+     *
+     * @see Character::rendition
+     */
+    void resetRendition(int rendition);
+    
+    /** 
+     * Sets the cursor's foreground color.
+     * @param space The color space used by the @p color argument
+     * @param color The new foreground color.  The meaning of this depends on
+     * the color @p space used.
+     *
+     * @see CharacterColor
+     */
+    void setForeColor  (int space, int color);
+    /**
+     * Sets the cursor's background color.
+     * @param space The color space used by the @p color argumnet.
+     * @param color The new background color.  The meaning of this depends on
+     * the color @p space used.
+     *
+     * @see CharacterColor
+     */
+    void setBackColor  (int space, int color);
+    /** 
+     * Resets the cursor's color back to the default and sets the 
+     * character's rendition flags back to the default settings.
+     */
+    void setDefaultRendition();
+    
+    /** Returns the column which the cursor is positioned at. */
+    int  getCursorX() const;
+    /** Returns the line which the cursor is positioned on. */
+    int  getCursorY() const;
+   
+	/** TODO Document me */ 
+	void clear();
+    /** 
+     * Sets the position of the cursor to the 'home' position at the top-left
+     * corner of the screen (0,0) 
+     */
+    void home();
+    /**
+     * Resets the state of the screen.  This resets the various screen modes
+     * back to their default states.  The cursor style and colors are reset
+     * (as if setDefaultRendition() had been called)
+     *
+     * <ul>
+     * <li>Line wrapping is enabled.</li>
+     * <li>Origin mode is disabled.</li>
+     * <li>Insert mode is disabled.</li>
+     * <li>Cursor mode is enabled.  TODO Document me</li>
+     * <li>Screen mode is disabled. TODO Document me</li>
+     * <li>New line mode is disabled.  TODO Document me</li>
+     * </ul>
+     *
+     * If @p clearScreen is true then the screen contents are erased entirely, 
+     * otherwise they are unaltered.
+     */
+    void reset(bool clearScreen = true);
+   
+    /** 
+     * Displays a new character at the current cursor position. 
+     * 
+     * If the cursor is currently positioned at the right-edge of the screen and
+     * line wrapping is enabled then the character is added at the start of a new 
+     * line below the current one.
+     *
+     * If the MODE_Insert screen mode is currently enabled then the character 
+     * is inserted at the current cursor position, otherwise it will replace the 
+     * character already at the current cursor position.  
+     */ 
+    void ShowCharacter(unsigned short c);
+    
+    // Do composition with last shown character FIXME: Not implemented yet for KDE 4
+    void compose(const QString& compose);
+    
+    /** 
+     * Resizes the image to a new fixed size of @p new_lines by @p new_columns.  
+     * In the case that @p new_columns is smaller than the current number of columns,
+     * existing lines are not truncated.  This prevents characters from being lost
+     * if the terminal display is resized smaller and then larger again.
+     *
+     * (note that in versions of Konsole prior to KDE 4, existing lines were
+     *  truncated when making the screen image smaller)
+     */
+    void resizeImage(int new_lines, int new_columns);
+    
+    /**
+     * Returns the current screen image.  
+     * The result is an array of Characters of size [getLines()][getColumns()] which
+     * must be freed by the caller after use.
+     *
+     * @param dest Buffer to copy the characters into
+     * @param size Size of @p dest in Characters
+     * @param startLine Index of first line to copy
+     * @param endLine Index of last line to copy
+     */
+    void getImage( Character* dest , int size , int startLine , int endLine ) const;
+
+    /** 
+     * Returns the additional attributes associated with lines in the image.
+     * The most important attribute is LINE_WRAPPED which specifies that the 
+     * line is wrapped,
+     * other attributes control the size of characters in the line.
+     */
+    QVector<LineProperty> getLineProperties( int startLine , int endLine ) const;
+	
+
+    /** Return the number of lines. */
+    int  getLines()   { return lines; }
+    /** Return the number of columns. */
+    int  getColumns() { return columns; }
+    /** Return the number of lines in the history buffer. */
+    int  getHistLines ();
+    /** 
+     * Sets the type of storage used to keep lines in the history. 
+     * If @p copyPreviousScroll is true then the contents of the previous 
+     * history buffer are copied into the new scroll.
+     */
+    void setScroll(const HistoryType& , bool copyPreviousScroll = true);
+    /** Returns the type of storage used to keep lines in the history. */
+    const HistoryType& getScroll();
+    /** 
+     * Returns true if this screen keeps lines that are scrolled off the screen
+     * in a history buffer.
+     */
+    bool hasScroll();
+
+    /** 
+     * Sets the start of the selection.
+     *
+     * @param column The column index of the first character in the selection.
+     * @param line The line index of the first character in the selection.
+     * @param columnmode True if the selection is in column mode.
+     */
+    void setSelectionStart(const int column, const int line, const bool columnmode);
+    
+    /**
+     * Sets the end of the current selection.
+     *
+     * @param column The column index of the last character in the selection.
+     * @param line The line index of the last character in the selection. 
+     */ 
+    void setSelectionEnd(const int column, const int line);
+   
+    /**
+     * Retrieves the start of the selection or the cursor position if there
+     * is no selection.
+     */
+    void getSelectionStart(int& column , int& line);
+    
+    /**
+     * Retrieves the end of the selection or the cursor position if there
+     * is no selection.
+     */
+    void getSelectionEnd(int& column , int& line);
+
+    /** Clears the current selection */
+    void clearSelection();
+
+    void setBusySelecting(bool busy) { sel_busy = busy; }
+
+    /** 
+ 	 * 	Returns true if the character at (@p column, @p line) is part of the
+ 	 *  current selection. 
+ 	 */ 
+    bool isSelected(const int column,const int line) const;
+
+    /** 
+     * Convenience method.  Returns the currently selected text. 
+     * @param preserveLineBreaks Specifies whether new line characters should 
+     * be inserted into the returned text at the end of each terminal line.
+     */
+    QString selectedText(bool preserveLineBreaks);
+	    
+	/**
+	 * Copies part of the output to a stream.
+	 *
+	 * @param decoder A decoder which coverts terminal characters into text
+	 * @param from The first line in the history to retrieve
+	 * @param to The last line in the history to retrieve
+	 */
+	void writeToStream(TerminalCharacterDecoder* decoder, int from, int to);
+
+    /** 
+     * Sets the selection to line @p no in the history and returns
+     * the text of that line from the history buffer.
+     */
+    QString getHistoryLine(int no);
+
+	/**
+	 * Copies the selected characters, set using @see setSelBeginXY and @see setSelExtentXY
+	 * into a stream.
+	 *
+	 * @param decoder A decoder which converts terminal characters into text.  
+	 * PlainTextDecoder is the most commonly used decoder which coverts characters 
+	 * into plain text with no formatting.
+     * @param preserveLineBreaks Specifies whether new line characters should 
+     * be inserted into the returned text at the end of each terminal line. 
+	 */
+	void writeSelectionToStream(TerminalCharacterDecoder* decoder , bool
+                                preserveLineBreaks = true);
+
+    /** TODO Document me */
+    void checkSelection(int from, int to);
+
+	/** 
+	 * Sets or clears an attribute of the current line.
+	 * 
+	 * @param property The attribute to set or clear
+	 * Possible properties are:
+	 * LINE_WRAPPED:	 Specifies that the line is wrapped.
+	 * LINE_DOUBLEWIDTH: Specifies that the characters in the current line should be double the normal width.
+	 * LINE_DOUBLEHEIGHT:Specifies that the characters in the current line should be double the normal height.
+     *                   Double-height lines are formed of two lines containing the same characters,
+     *                   with both having the LINE_DOUBLEHEIGHT attribute.  This allows other parts of the 
+     *                   code to work on the assumption that all lines are the same height.
+	 *
+	 * @param enable true to apply the attribute to the current line or false to remove it
+	 */
+	void setLineProperty(LineProperty property , bool enable);
+
+
+    /** 
+     * Returns the number of lines that the image has been scrolled up or down by,
+     * since the last call to resetScrolledLines().
+     *
+     * a positive return value indicates that the image has been scrolled up,
+     * a negative return value indicates that the image has been scrolled down. 
+     */
+    int scrolledLines() const;
+
+    /**
+     * Returns the region of the image which was last scrolled.
+     *
+     * This is the area of the image from the top margin to the 
+     * bottom margin when the last scroll occurred.
+     */
+    QRect lastScrolledRegion() const;
+
+    /** 
+     * Resets the count of the number of lines that the image has been scrolled up or down by,
+     * see scrolledLines()
+     */
+    void resetScrolledLines();
+
+    /**
+     * Returns the number of lines of output which have been
+     * dropped from the history since the last call
+     * to resetDroppedLines()
+     *
+     * If the history is not unlimited then it will drop
+     * the oldest lines of output if new lines are added when
+     * it is full.  
+     */
+    int droppedLines() const;
+
+    /**
+     * Resets the count of the number of lines dropped from
+     * the history.
+     */
+    void resetDroppedLines();
+
+	/** 
+ 	 * Fills the buffer @p dest with @p count instances of the default (ie. blank)
+ 	 * Character style.
+ 	 */
+	static void fillWithDefaultChar(Character* dest, int count);
+
+private: 
+
+	//copies a line of text from the screen or history into a stream using a 
+	//specified character decoder
+	//line - the line number to copy, from 0 (the earliest line in the history) up to 
+	//		 hist->getLines() + lines - 1
+	//start - the first column on the line to copy
+	//count - the number of characters on the line to copy
+	//decoder - a decoder which coverts terminal characters (an Character array) into text
+    //appendNewLine - if true a new line character (\n) is appended to the end of the line
+	void copyLineToStream(int line, 
+                          int start, 
+                          int count, 
+                          TerminalCharacterDecoder* decoder,
+                          bool appendNewLine,
+                          bool preserveLineBreaks);
+	
+    //fills a section of the screen image with the character 'c'
+    //the parameters are specified as offsets from the start of the screen image.
+    //the loc(x,y) macro can be used to generate these values from a column,line pair.
+    void clearImage(int loca, int loce, char c);
+
+    //move screen image between 'sourceBegin' and 'sourceEnd' to 'dest'.
+    //the parameters are specified as offsets from the start of the screen image.
+    //the loc(x,y) macro can be used to generate these values from a column,line pair.
+    void moveImage(int dest, int sourceBegin, int sourceEnd);
+    
+    void scrollUp(int from, int i);
+    void scrollDown(int from, int i);
+
+    void addHistLine();
+
+    void initTabStops();
+
+    void effectiveRendition();
+    void reverseRendition(Character& p) const;
+
+    bool isSelectionValid() const;
+
+	// copies 'count' lines from the screen buffer into 'dest',
+	// starting from 'startLine', where 0 is the first line in the screen buffer
+	void copyFromScreen(Character* dest, int startLine, int count) const;
+	// copies 'count' lines from the history buffer into 'dest',
+	// starting from 'startLine', where 0 is the first line in the history
+	void copyFromHistory(Character* dest, int startLine, int count) const;
+
+
+    // screen image ----------------
+    int lines;
+    int columns;
+
+    typedef QVector<Character> ImageLine;      // [0..columns]
+    ImageLine*          screenLines;    // [lines]
+
+    int _scrolledLines;
+    QRect _lastScrolledRegion;
+
+    int _droppedLines;
+
+    QVarLengthArray<LineProperty,64> lineProperties;    
+	
+    // history buffer ---------------
+    HistoryScroll *hist;
+    
+    // cursor location
+    int cuX;
+    int cuY;
+
+    // cursor color and rendition info
+    CharacterColor cu_fg;      // foreground
+    CharacterColor cu_bg;      // background
+    quint8 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.
+    bool sel_busy; // Busy making a selection.
+    bool columnmode;  // Column selection mode
+
+    // effective colors and rendition ------------
+    CharacterColor ef_fg;      // These are derived from
+    CharacterColor ef_bg;      // the cu_* variables above
+    quint8 ef_re;      // to speed up operation
+
+    //
+    // save cursor, rendition & states ------------
+    // 
+
+    // cursor location
+    int sa_cuX;
+    int sa_cuY;
+
+    // rendition info
+    quint8 sa_cu_re;
+    CharacterColor sa_cu_fg;
+    CharacterColor sa_cu_bg;
+    
+    // last position where we added a character
+    int lastPos;
+
+    // modes
+    ScreenParm saveParm;
+
+    static Character defaultChar;
+};
+
+}
+
+#endif // SCREEN_H
new file mode 100644
--- /dev/null
+++ b/gui//ScreenWindow.cpp
@@ -0,0 +1,296 @@
+/*
+    Copyright (C) 2007 by Robert Knight <robertknight@gmail.com>
+
+    Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301  USA.
+*/
+
+// Own
+#include "ScreenWindow.h"
+
+// Qt
+#include <QtCore>
+
+// Konsole
+#include "Screen.h"
+
+using namespace Konsole;
+
+ScreenWindow::ScreenWindow(QObject* parent)
+    : QObject(parent)
+	, _windowBuffer(0)
+	, _windowBufferSize(0)
+	, _bufferNeedsUpdate(true)
+	, _windowLines(1)
+    , _currentLine(0)
+    , _trackOutput(true)
+    , _scrollCount(0)
+{
+}
+ScreenWindow::~ScreenWindow()
+{
+	delete[] _windowBuffer;
+}
+void ScreenWindow::setScreen(Screen* screen)
+{
+    Q_ASSERT( screen );
+
+    _screen = screen;
+}
+
+Screen* ScreenWindow::screen() const
+{
+    return _screen;
+}
+
+Character* ScreenWindow::getImage()
+{
+	// reallocate internal buffer if the window size has changed
+	int size = windowLines() * windowColumns();
+	if (_windowBuffer == 0 || _windowBufferSize != size) 
+	{
+		delete[] _windowBuffer;
+		_windowBufferSize = size;
+		_windowBuffer = new Character[size];
+		_bufferNeedsUpdate = true;
+	}
+
+	 if (!_bufferNeedsUpdate)
+		return _windowBuffer;
+ 
+	_screen->getImage(_windowBuffer,size,
+					  currentLine(),endWindowLine());
+
+	// this window may look beyond the end of the screen, in which 
+	// case there will be an unused area which needs to be filled
+	// with blank characters
+	fillUnusedArea();
+
+	_bufferNeedsUpdate = false;
+	return _windowBuffer;
+}
+
+void ScreenWindow::fillUnusedArea()
+{
+	int screenEndLine = _screen->getHistLines() + _screen->getLines() - 1;
+	int windowEndLine = currentLine() + windowLines() - 1;
+
+	int unusedLines = windowEndLine - screenEndLine;
+	int charsToFill = unusedLines * windowColumns();
+
+	Screen::fillWithDefaultChar(_windowBuffer + _windowBufferSize - charsToFill,charsToFill); 
+}
+
+// return the index of the line at the end of this window, or if this window 
+// goes beyond the end of the screen, the index of the line at the end
+// of the screen.
+//
+// when passing a line number to a Screen method, the line number should
+// never be more than endWindowLine()
+//
+int ScreenWindow::endWindowLine() const
+{
+	return qMin(currentLine() + windowLines() - 1,
+				lineCount() - 1);
+}
+QVector<LineProperty> ScreenWindow::getLineProperties()
+{
+    QVector<LineProperty> result = _screen->getLineProperties(currentLine(),endWindowLine());
+	
+	if (result.count() != windowLines())
+		result.resize(windowLines());
+
+	return result;
+}
+
+QString ScreenWindow::selectedText( bool preserveLineBreaks ) const
+{
+    return _screen->selectedText( preserveLineBreaks );
+}
+
+void ScreenWindow::getSelectionStart( int& column , int& line )
+{
+    _screen->getSelectionStart(column,line);
+    line -= currentLine();
+}
+void ScreenWindow::getSelectionEnd( int& column , int& line )
+{
+    _screen->getSelectionEnd(column,line);
+    line -= currentLine();
+}
+void ScreenWindow::setSelectionStart( int column , int line , bool columnMode )
+{
+    _screen->setSelectionStart( column , qMin(line + currentLine(),endWindowLine())  , columnMode);
+	
+	_bufferNeedsUpdate = true;
+    emit selectionChanged();
+}
+
+void ScreenWindow::setSelectionEnd( int column , int line )
+{
+    _screen->setSelectionEnd( column , qMin(line + currentLine(),endWindowLine()) );
+
+	_bufferNeedsUpdate = true;
+    emit selectionChanged();
+}
+
+bool ScreenWindow::isSelected( int column , int line )
+{
+    return _screen->isSelected( column , qMin(line + currentLine(),endWindowLine()) );
+}
+
+void ScreenWindow::clearSelection()
+{
+    _screen->clearSelection();
+
+    emit selectionChanged();
+}
+
+void ScreenWindow::setWindowLines(int lines)
+{
+	Q_ASSERT(lines > 0);
+	_windowLines = lines;
+}
+int ScreenWindow::windowLines() const
+{
+	return _windowLines;		
+}
+
+int ScreenWindow::windowColumns() const
+{
+    return _screen->getColumns();
+}
+
+int ScreenWindow::lineCount() const
+{
+    return _screen->getHistLines() + _screen->getLines();
+}
+
+int ScreenWindow::columnCount() const
+{
+    return _screen->getColumns();
+}
+
+QPoint ScreenWindow::cursorPosition() const
+{
+    QPoint position;
+    
+    position.setX( _screen->getCursorX() );
+    position.setY( _screen->getCursorY() );
+
+    return position; 
+}
+
+int ScreenWindow::currentLine() const
+{
+    return qBound(0,_currentLine,lineCount()-windowLines());
+}
+
+void ScreenWindow::scrollBy( RelativeScrollMode mode , int amount )
+{
+    if ( mode == ScrollLines )
+    {
+        scrollTo( currentLine() + amount );
+    }
+    else if ( mode == ScrollPages )
+    {
+        scrollTo( currentLine() + amount * ( windowLines() / 2 ) ); 
+    }
+}
+
+bool ScreenWindow::atEndOfOutput() const
+{
+    return currentLine() == (lineCount()-windowLines());
+}
+
+void ScreenWindow::scrollTo( int line )
+{
+	int maxCurrentLineNumber = lineCount() - windowLines();
+	line = qBound(0,line,maxCurrentLineNumber);
+
+    const int delta = line - _currentLine;
+    _currentLine = line;
+
+    // keep track of number of lines scrolled by,
+    // this can be reset by calling resetScrollCount()
+    _scrollCount += delta;
+
+    _bufferNeedsUpdate = true;
+
+    emit scrolled(_currentLine);
+}
+
+void ScreenWindow::setTrackOutput(bool trackOutput)
+{
+    _trackOutput = trackOutput;
+}
+
+bool ScreenWindow::trackOutput() const
+{
+    return _trackOutput;
+}
+
+int ScreenWindow::scrollCount() const
+{
+    return _scrollCount;
+}
+
+void ScreenWindow::resetScrollCount() 
+{
+    _scrollCount = 0;
+}
+
+QRect ScreenWindow::scrollRegion() const
+{
+	bool equalToScreenSize = windowLines() == _screen->getLines();
+
+	if ( atEndOfOutput() && equalToScreenSize )
+    	return _screen->lastScrolledRegion();
+	else
+		return QRect(0,0,windowColumns(),windowLines());
+}
+
+void ScreenWindow::notifyOutputChanged()
+{
+    // move window to the bottom of the screen and update scroll count
+    // if this window is currently tracking the bottom of the screen
+    if ( _trackOutput )
+    { 
+        _scrollCount -= _screen->scrolledLines();
+        _currentLine = qMax(0,_screen->getHistLines() - (windowLines()-_screen->getLines()));
+    }
+    else
+    {
+        // if the history is not unlimited then it may 
+        // have run out of space and dropped the oldest
+        // lines of output - in this case the screen
+        // window's current line number will need to 
+        // be adjusted - otherwise the output will scroll
+        _currentLine = qMax(0,_currentLine - 
+                              _screen->droppedLines());
+
+        // ensure that the screen window's current position does
+        // not go beyond the bottom of the screen
+        _currentLine = qMin( _currentLine , _screen->getHistLines() );
+    }
+
+	_bufferNeedsUpdate = true;
+
+    emit outputChanged(); 
+}
+
+//#include "moc_ScreenWindow.cpp"
new file mode 100644
--- /dev/null
+++ b/gui//ScreenWindow.h
@@ -0,0 +1,256 @@
+/*
+    Copyright (C) 2007 by Robert Knight <robertknight@gmail.com>
+
+    Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301  USA.
+*/
+
+#ifndef SCREENWINDOW_H
+#define SCREENWINDOW_H
+
+// Qt
+#include <QtCore/QObject>
+#include <QtCore/QPoint>
+#include <QtCore/QRect>
+
+// Konsole
+#include "Character.h"
+
+namespace Konsole
+{
+
+class Screen;
+
+/**
+ * Provides a window onto a section of a terminal screen.
+ * This window can then be rendered by a terminal display widget ( TerminalDisplay ).
+ *
+ * To use the screen window, create a new ScreenWindow() instance and associated it with 
+ * a terminal screen using setScreen().
+ * Use the scrollTo() method to scroll the window up and down on the screen.
+ * Call the getImage() method to retrieve the character image which is currently visible in the window.
+ *
+ * setTrackOutput() controls whether the window moves to the bottom of the associated screen when new
+ * lines are added to it.
+ *
+ * Whenever the output from the underlying screen is changed, the notifyOutputChanged() slot should
+ * be called.  This in turn will update the window's position and emit the outputChanged() signal
+ * if necessary.
+ */
+class ScreenWindow : public QObject
+{
+Q_OBJECT
+
+public:
+    /** 
+     * Constructs a new screen window with the given parent.
+     * A screen must be specified by calling setScreen() before calling getImage() or getLineProperties().
+     *
+     * You should not call this constructor directly, instead use the Emulation::createWindow() method
+     * to create a window on the emulation which you wish to view.  This allows the emulation
+     * to notify the window when the associated screen has changed and synchronize selection updates
+     * between all views on a session.
+     */
+    ScreenWindow(QObject* parent = 0);
+	virtual ~ScreenWindow();
+
+    /** Sets the screen which this window looks onto */
+    void setScreen(Screen* screen);
+    /** Returns the screen which this window looks onto */
+    Screen* screen() const;
+
+    /** 
+     * Returns the image of characters which are currently visible through this window
+     * onto the screen.
+     *
+     * The buffer is managed by the ScreenWindow instance and does not need to be
+     * deleted by the caller.
+     */
+    Character* getImage();
+
+    /**
+     * Returns the line attributes associated with the lines of characters which
+     * are currently visible through this window
+     */
+    QVector<LineProperty> getLineProperties();
+
+    /**
+     * Returns the number of lines which the region of the window
+     * specified by scrollRegion() has been scrolled by since the last call 
+     * to resetScrollCount().  scrollRegion() is in most cases the 
+     * whole window, but will be a smaller area in, for example, applications
+     * which provide split-screen facilities.
+     *
+     * This is not guaranteed to be accurate, but allows views to optimise
+     * rendering by reducing the amount of costly text rendering that
+     * needs to be done when the output is scrolled. 
+     */
+    int scrollCount() const;
+
+    /**
+     * Resets the count of scrolled lines returned by scrollCount()
+     */
+    void resetScrollCount();
+
+    /**
+     * Returns the area of the window which was last scrolled, this is 
+     * usually the whole window area.
+     *
+     * Like scrollCount(), this is not guaranteed to be accurate,
+     * but allows views to optimise rendering.
+     */
+    QRect scrollRegion() const;
+
+    /** 
+     * Sets the start of the selection to the given @p line and @p column within 
+     * the window.
+     */
+    void setSelectionStart( int column , int line , bool columnMode );
+    /**
+     * Sets the end of the selection to the given @p line and @p column within
+     * the window.
+     */
+    void setSelectionEnd( int column , int line ); 
+    /**
+     * Retrieves the start of the selection within the window.
+     */
+    void getSelectionStart( int& column , int& line );
+    /**
+     * Retrieves the end of the selection within the window.
+     */
+    void getSelectionEnd( int& column , int& line );
+    /**
+     * Returns true if the character at @p line , @p column is part of the selection.
+     */
+    bool isSelected( int column , int line );
+    /** 
+     * Clears the current selection
+     */
+    void clearSelection();
+
+	/** Sets the number of lines in the window */
+	void setWindowLines(int lines);
+    /** Returns the number of lines in the window */
+    int windowLines() const;
+    /** Returns the number of columns in the window */
+    int windowColumns() const;
+    
+    /** Returns the total number of lines in the screen */
+    int lineCount() const;
+    /** Returns the total number of columns in the screen */
+    int columnCount() const;
+
+    /** Returns the index of the line which is currently at the top of this window */
+    int currentLine() const;
+
+    /** 
+     * Returns the position of the cursor 
+     * within the window.
+     */
+    QPoint cursorPosition() const;
+
+    /** 
+     * Convenience method. Returns true if the window is currently at the bottom
+     * of the screen.
+     */
+    bool atEndOfOutput() const;
+
+    /** Scrolls the window so that @p line is at the top of the window */
+    void scrollTo( int line );
+
+    enum RelativeScrollMode
+    {
+        ScrollLines,
+        ScrollPages
+    };
+
+    /** 
+     * Scrolls the window relative to its current position on the screen.
+     *
+     * @param mode Specifies whether @p amount refers to the number of lines or the number
+     * of pages to scroll.    
+     * @param amount The number of lines or pages ( depending on @p mode ) to scroll by.  If
+     * this number is positive, the view is scrolled down.  If this number is negative, the view
+     * is scrolled up.
+     */
+    void scrollBy( RelativeScrollMode mode , int amount );
+
+    /** 
+     * Specifies whether the window should automatically move to the bottom
+     * of the screen when new output is added.
+     *
+     * If this is set to true, the window will be moved to the bottom of the associated screen ( see 
+     * screen() ) when the notifyOutputChanged() method is called.
+     */
+    void setTrackOutput(bool trackOutput);
+    /** 
+     * Returns whether the window automatically moves to the bottom of the screen as
+     * new output is added.  See setTrackOutput()
+     */
+    bool trackOutput() const;
+
+    /**
+     * Returns the text which is currently selected.
+     *
+     * @param preserveLineBreaks See Screen::selectedText()
+     */
+    QString selectedText( bool preserveLineBreaks ) const;
+
+public slots:
+    /** 
+     * Notifies the window that the contents of the associated terminal screen have changed.
+     * This moves the window to the bottom of the screen if trackOutput() is true and causes
+     * the outputChanged() signal to be emitted.
+     */
+    void notifyOutputChanged();
+
+signals:
+    /**
+     * Emitted when the contents of the associated terminal screen ( see screen() ) changes. 
+     */
+    void outputChanged();
+
+    /**
+     * Emitted when the screen window is scrolled to a different position.
+     * 
+     * @param line The line which is now at the top of the window.
+     */
+    void scrolled(int line);
+
+    /**
+     * Emitted when the selection is changed.
+     */
+    void selectionChanged();
+
+private:
+	int endWindowLine() const;
+	void fillUnusedArea();
+
+    Screen* _screen; // see setScreen() , screen()
+	Character* _windowBuffer;
+	int _windowBufferSize;
+	bool _bufferNeedsUpdate;
+
+	int  _windowLines;
+    int  _currentLine; // see scrollTo() , currentLine()
+    bool _trackOutput; // see setTrackOutput() , trackOutput() 
+    int  _scrollCount; // count of lines which the window has been scrolled by since
+                       // the last call to resetScrollCount()
+};
+
+}
+#endif // SCREENWINDOW_H
new file mode 100644
--- /dev/null
+++ b/gui//Session.cpp
@@ -0,0 +1,1021 @@
+/*
+    This file is part of Konsole
+
+    Copyright (C) 2006-2007 by Robert Knight <robertknight@gmail.com>
+    Copyright (C) 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
+
+    Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301  USA.
+*/
+
+// Own
+#include "Session.h"
+
+// Standard
+#include <assert.h>
+#include <stdlib.h>
+
+// Qt
+#include <QtGui/QApplication>
+#include <QtCore/QByteRef>
+#include <QtCore/QDir>
+#include <QtCore/QFile>
+#include <QtCore/QRegExp>
+#include <QtCore/QStringList>
+#include <QtCore>
+
+#include "Pty.h"
+#include "TerminalDisplay.h"
+#include "ShellCommand.h"
+#include "Vt102Emulation.h"
+
+using namespace Konsole;
+
+int Session::lastSessionId = 0;
+
+Session::Session() :
+    _shellProcess(0)
+   , _emulation(0)
+   , _monitorActivity(false)
+   , _monitorSilence(false)
+   , _notifiedActivity(false)
+   , _autoClose(true)
+   , _wantedClose(false)
+   , _silenceSeconds(10)
+   , _addToUtmp(false)  // disabled by default because of a bug encountered on certain systems
+                        // which caused Konsole to hang when closing a tab and then opening a new
+                        // one.  A 'QProcess destroyed while still running' warning was being
+                        // printed to the terminal.  Likely a problem in KPty::logout() 
+                        // or KPty::login() which uses a QProcess to start /usr/bin/utempter 
+   , _flowControl(true)
+   , _fullScripting(false)
+   , _sessionId(0)
+//   , _zmodemBusy(false)
+//   , _zmodemProc(0)
+//   , _zmodemProgress(0)
+   , _hasDarkBackground(false)
+{
+    //prepare DBus communication
+//    new SessionAdaptor(this);
+    _sessionId = ++lastSessionId;
+//    QDBusConnection::sessionBus().registerObject(QLatin1String("/Sessions/")+QString::number(_sessionId), this);
+
+    //create teletype for I/O with shell process
+    _shellProcess = new Pty();
+
+    //create emulation backend
+    _emulation = new Vt102Emulation();
+
+    connect( _emulation, SIGNAL( titleChanged( int, const QString & ) ),
+           this, SLOT( setUserTitle( int, const QString & ) ) );
+    connect( _emulation, SIGNAL( stateSet(int) ),
+           this, SLOT( activityStateSet(int) ) );
+//    connect( _emulation, SIGNAL( zmodemDetected() ), this ,
+//            SLOT( fireZModemDetected() ) );
+    connect( _emulation, SIGNAL( changeTabTextColorRequest( int ) ),
+           this, SIGNAL( changeTabTextColorRequest( int ) ) );
+    connect( _emulation, SIGNAL(profileChangeCommandReceived(const QString&)),
+           this, SIGNAL( profileChangeCommandReceived(const QString&)) );
+    // TODO
+    // connect( _emulation,SIGNAL(imageSizeChanged(int,int)) , this ,
+    //        SLOT(onEmulationSizeChange(int,int)) );
+
+    //connect teletype to emulation backend
+    _shellProcess->setUtf8Mode(_emulation->utf8());
+
+    connect( _shellProcess,SIGNAL(receivedData(const char*,int)),this,
+            SLOT(onReceiveBlock(const char*,int)) );
+    connect( _emulation,SIGNAL(sendData(const char*,int)),_shellProcess,
+            SLOT(sendData(const char*,int)) );
+    connect( _emulation,SIGNAL(lockPtyRequest(bool)),_shellProcess,SLOT(lockPty(bool)) );
+    connect( _emulation,SIGNAL(useUtf8Request(bool)),_shellProcess,SLOT(setUtf8Mode(bool)) );
+
+
+    connect( _shellProcess,SIGNAL(done(int)), this, SLOT(done(int)) );
+
+    //setup timer for monitoring session activity
+    _monitorTimer = new QTimer(this);
+    _monitorTimer->setSingleShot(true);
+    connect(_monitorTimer, SIGNAL(timeout()), this, SLOT(monitorTimerDone()));
+}
+
+WId Session::windowId() const
+{
+    // Returns a window ID for this session which is used
+    // to set the WINDOWID environment variable in the shell
+    // process.
+    //
+    // Sessions can have multiple views or no views, which means
+    // that a single ID is not always going to be accurate.
+    //
+    // If there are no views, the window ID is just 0.  If
+    // there are multiple views, then the window ID for the
+    // top-level window which contains the first view is
+    // returned
+
+    if ( _views.count() == 0 )
+       return 0;
+    else
+    {
+        QWidget* window = _views.first();
+
+        Q_ASSERT( window );
+
+        while ( window->parentWidget() != 0 )
+            window = window->parentWidget();
+
+        return window->winId();
+    }
+}
+
+void Session::setDarkBackground(bool darkBackground)
+{
+    _hasDarkBackground = darkBackground;
+}
+bool Session::hasDarkBackground() const
+{
+    return _hasDarkBackground;
+}
+bool Session::isRunning() const
+{
+    return _shellProcess->isRunning();
+}
+
+void Session::setCodec(QTextCodec* codec)
+{
+    emulation()->setCodec(codec);
+}
+
+void Session::setProgram(const QString& program)
+{
+    _program = ShellCommand::expand(program);
+}
+void Session::setInitialWorkingDirectory(const QString& dir)
+{
+    _initialWorkingDir = ShellCommand::expand(dir);
+}
+void Session::setArguments(const QStringList& arguments)
+{
+    _arguments = ShellCommand::expand(arguments);
+}
+
+QList<TerminalDisplay*> Session::views() const
+{
+    return _views;
+}
+
+void Session::addView(TerminalDisplay* widget)
+{
+     Q_ASSERT( !_views.contains(widget) );
+
+    _views.append(widget);
+
+    if ( _emulation != 0 )
+    {
+        // connect emulation - view signals and slots
+        connect( widget , SIGNAL(keyPressedSignal(QKeyEvent*)) , _emulation ,
+               SLOT(sendKeyEvent(QKeyEvent*)) );
+        connect( widget , SIGNAL(mouseSignal(int,int,int,int)) , _emulation ,
+               SLOT(sendMouseEvent(int,int,int,int)) );
+        connect( widget , SIGNAL(sendStringToEmu(const char*)) , _emulation ,
+               SLOT(sendString(const char*)) );
+
+        // allow emulation to notify view when the foreground process
+        // indicates whether or not it is interested in mouse signals
+        connect( _emulation , SIGNAL(programUsesMouseChanged(bool)) , widget ,
+               SLOT(setUsesMouse(bool)) );
+
+        widget->setUsesMouse( _emulation->programUsesMouse() );
+
+        widget->setScreenWindow(_emulation->createWindow());
+    }
+
+    //connect view signals and slots
+    QObject::connect( widget ,SIGNAL(changedContentSizeSignal(int,int)),this,
+                    SLOT(onViewSizeChange(int,int)));
+
+    QObject::connect( widget ,SIGNAL(destroyed(QObject*)) , this ,
+                    SLOT(viewDestroyed(QObject*)) );
+//slot for close
+    QObject::connect(this, SIGNAL(finished()), widget, SLOT(close()));		    
+    
+}
+
+void Session::viewDestroyed(QObject* view)
+{
+    TerminalDisplay* display = (TerminalDisplay*)view;
+
+    Q_ASSERT( _views.contains(display) );
+
+    removeView(display);
+}
+
+void Session::removeView(TerminalDisplay* widget)
+{
+    _views.removeAll(widget);
+
+	disconnect(widget,0,this,0);
+
+    if ( _emulation != 0 )
+    {
+        // disconnect
+        //  - key presses signals from widget
+        //  - mouse activity signals from widget
+        //  - string sending signals from widget
+        //
+        //  ... and any other signals connected in addView()
+        disconnect( widget, 0, _emulation, 0);
+
+        // disconnect state change signals emitted by emulation
+        disconnect( _emulation , 0 , widget , 0);
+    }
+
+	// close the session automatically when the last view is removed
+	if ( _views.count() == 0 )
+	{
+		close();
+	}
+}
+
+void Session::run()
+{
+  //check that everything is in place to run the session
+  if (_program.isEmpty())
+      qDebug() << "Session::run() - program to run not set.";
+  if (_arguments.isEmpty())
+      qDebug() << "Session::run() - no command line arguments specified.";
+
+  // Upon a KPty error, there is no description on what that error was...
+  // Check to see if the given program is executable.
+  QString exec = QFile::encodeName(_program);
+
+  // if 'exec' is not specified, fall back to default shell.  if that 
+  // is not set then fall back to /bin/sh
+  if ( exec.isEmpty() )
+      exec = getenv("SHELL");
+  if ( exec.isEmpty() )
+  	  exec = "/bin/sh";
+
+  // if no arguments are specified, fall back to shell
+  QStringList arguments =  _arguments.join(QChar(' ')).isEmpty() ?
+                                    QStringList() << exec : _arguments;
+  QString pexec = exec;
+
+  if ( pexec.isEmpty() ) {
+    qDebug()<<"can not execute "<<exec<<endl;
+    QTimer::singleShot(1, this, SIGNAL(finished()));
+    return;
+  }
+
+  QString cwd_save = QDir::currentPath();
+  if (!_initialWorkingDir.isEmpty())
+    _shellProcess->setWorkingDirectory(_initialWorkingDir);
+  else
+    _shellProcess->setWorkingDirectory(QDir::homePath());
+
+  _shellProcess->setXonXoff(_flowControl);
+  _shellProcess->setErase(_emulation->getErase());
+
+  // this is not strictly accurate use of the COLORFGBG variable.  This does not
+  // tell the terminal exactly which colors are being used, but instead approximates
+  // the color scheme as "black on white" or "white on black" depending on whether
+  // the background color is deemed dark or not
+  QString backgroundColorHint = _hasDarkBackground ? "COLORFGBG=15;0" : "COLORFGBG=0;15";
+
+  int result = _shellProcess->start(QFile::encodeName(_program),
+                                  arguments,
+                                  _environment << backgroundColorHint,
+                                  windowId(),
+                                  _addToUtmp);
+
+  if (result < 0)
+  {
+    return;
+  }
+
+  _shellProcess->setWriteable(false);  // We are reachable via kwrited.
+
+  emit started();
+}
+
+void Session::setUserTitle( int what, const QString &caption )
+{
+    //set to true if anything is actually changed (eg. old _nameTitle != new _nameTitle )
+	bool modified = false;
+
+    // (btw: what=0 changes _userTitle and icon, what=1 only icon, what=2 only _nameTitle
+    if ((what == 0) || (what == 2)) 
+    {
+       	if ( _userTitle != caption ) {
+			_userTitle = caption;
+			modified = true;
+		}
+    }
+
+    if ((what == 0) || (what == 1))
+	{
+		if ( _iconText != caption ) {
+       		_iconText = caption;
+			modified = true;
+		}
+	}
+
+    if (what == 11) 
+    {
+      QString colorString = caption.section(';',0,0);
+      qDebug() << __FILE__ << __LINE__ << ": setting background colour to " << colorString;
+      QColor backColor = QColor(colorString);
+      if (backColor.isValid()){// change color via \033]11;Color\007
+          if (backColor != _modifiedBackground)
+          {
+              _modifiedBackground = backColor;
+
+              // bail out here until the code to connect the terminal display
+              // to the changeBackgroundColor() signal has been written
+              // and tested - just so we don't forget to do this.
+              Q_ASSERT( 0 );
+
+              emit changeBackgroundColorRequest(backColor);
+          }
+      }
+    }
+
+	if (what == 30) 
+    {
+		if ( _nameTitle != caption ) {
+       		setTitle(Session::NameRole,caption);
+			return;
+		}
+	}
+
+    if (what == 31) 
+    {
+       QString cwd=caption;
+       cwd=cwd.replace( QRegExp("^~"), QDir::homePath() );
+       emit openUrlRequest(cwd);
+	}
+
+    // change icon via \033]32;Icon\007
+    if (what == 32) 
+    { 
+    	if ( _iconName != caption ) {
+	   		_iconName = caption;
+
+			modified = true;
+		}
+    }
+
+    if (what == 50) 
+    {
+        emit profileChangeCommandReceived(caption);
+        return;
+    }
+
+	if ( modified )
+    	emit titleChanged();
+}
+
+QString Session::userTitle() const
+{
+    return _userTitle;
+}
+void Session::setTabTitleFormat(TabTitleContext context , const QString& format)
+{
+    if ( context == LocalTabTitle )
+        _localTabTitleFormat = format;
+    else if ( context == RemoteTabTitle )
+        _remoteTabTitleFormat = format;
+}
+QString Session::tabTitleFormat(TabTitleContext context) const
+{
+    if ( context == LocalTabTitle )
+        return _localTabTitleFormat;
+    else if ( context == RemoteTabTitle )
+        return _remoteTabTitleFormat;
+
+    return QString();
+}
+
+void Session::monitorTimerDone()
+{
+  //FIXME: The idea here is that the notification popup will appear to tell the user than output from
+  //the terminal has stopped and the popup will disappear when the user activates the session.
+  //
+  //This breaks with the addition of multiple views of a session.  The popup should disappear
+  //when any of the views of the session becomes active
+  
+
+  //FIXME: Make message text for this notification and the activity notification more descriptive.	
+  if (_monitorSilence) {
+//    KNotification::event("Silence", ("Silence in session '%1'", _nameTitle), QPixmap(),
+//                    QApplication::activeWindow(),
+//                    KNotification::CloseWhenWidgetActivated);
+    emit stateChanged(NOTIFYSILENCE);
+  }
+  else
+  {
+    emit stateChanged(NOTIFYNORMAL);
+  }
+
+  _notifiedActivity=false;
+}
+
+void Session::activityStateSet(int state)
+{
+  if (state==NOTIFYBELL)
+  {
+      QString s; s.sprintf("Bell in session '%s'",_nameTitle.toAscii().data());
+      
+      emit bellRequest( s );
+  }
+  else if (state==NOTIFYACTIVITY)
+  {
+    if (_monitorSilence) {
+      _monitorTimer->start(_silenceSeconds*1000);
+    }
+
+    if ( _monitorActivity ) {
+      //FIXME:  See comments in Session::monitorTimerDone()
+      if (!_notifiedActivity) {
+//        KNotification::event("Activity", ("Activity in session '%1'", _nameTitle), QPixmap(),
+//                        QApplication::activeWindow(),
+//        KNotification::CloseWhenWidgetActivated);
+        _notifiedActivity=true;
+      }
+    }
+  }
+
+  if ( state==NOTIFYACTIVITY && !_monitorActivity )
+          state = NOTIFYNORMAL;
+  if ( state==NOTIFYSILENCE && !_monitorSilence )
+          state = NOTIFYNORMAL;
+
+  emit stateChanged(state);
+}
+
+void Session::onViewSizeChange(int /*height*/, int /*width*/)
+{
+  updateTerminalSize();
+}
+void Session::onEmulationSizeChange(int lines , int columns)
+{
+  setSize( QSize(lines,columns) );
+}
+
+void Session::updateTerminalSize()
+{
+    QListIterator<TerminalDisplay*> viewIter(_views);
+
+    int minLines = -1;
+    int minColumns = -1;
+
+    // minimum number of lines and columns that views require for
+    // their size to be taken into consideration ( to avoid problems
+    // with new view widgets which haven't yet been set to their correct size )
+    const int VIEW_LINES_THRESHOLD = 2;
+    const int VIEW_COLUMNS_THRESHOLD = 2;
+
+    //select largest number of lines and columns that will fit in all visible views
+    while ( viewIter.hasNext() )
+    {
+        TerminalDisplay* view = viewIter.next();
+        if ( view->isHidden() == false &&
+             view->lines() >= VIEW_LINES_THRESHOLD &&
+             view->columns() >= VIEW_COLUMNS_THRESHOLD )
+        {
+            minLines = (minLines == -1) ? view->lines() : qMin( minLines , view->lines() );
+            minColumns = (minColumns == -1) ? view->columns() : qMin( minColumns , view->columns() );
+        }
+    }
+
+    // backend emulation must have a _terminal of at least 1 column x 1 line in size
+    if ( minLines > 0 && minColumns > 0 )
+    {
+        _emulation->setImageSize( minLines , minColumns );
+        _shellProcess->setWindowSize( minLines , minColumns );
+    }
+}
+
+void Session::refresh()
+{
+    // attempt to get the shell process to redraw the display
+    //
+    // this requires the program running in the shell
+    // to cooperate by sending an update in response to
+    // a window size change
+    //
+    // the window size is changed twice, first made slightly larger and then
+    // resized back to its normal size so that there is actually a change
+    // in the window size (some shells do nothing if the
+    // new and old sizes are the same)
+    //
+    // if there is a more 'correct' way to do this, please
+    // send an email with method or patches to konsole-devel@kde.org
+
+    const QSize existingSize = _shellProcess->windowSize();
+    _shellProcess->setWindowSize(existingSize.height(),existingSize.width()+1);
+    _shellProcess->setWindowSize(existingSize.height(),existingSize.width());
+}
+
+bool Session::sendSignal(int signal)
+{
+  return _shellProcess->kill(signal);
+}
+
+void Session::close()
+{
+  _autoClose = true;
+  _wantedClose = true;
+  if (!_shellProcess->isRunning() || !sendSignal(SIGHUP))
+  {
+     // Forced close.
+     QTimer::singleShot(1, this, SIGNAL(finished()));
+  }
+}
+
+void Session::sendText(const QString &text) const
+{
+  _emulation->sendText(text);
+}
+
+Session::~Session()
+{
+  delete _emulation;
+  delete _shellProcess;
+//  delete _zmodemProc;
+}
+
+void Session::setProfileKey(const QString& key)
+{
+    _profileKey = key;
+    emit profileChanged(key);
+}
+QString Session::profileKey() const { return _profileKey; }
+
+void Session::done(int exitStatus)
+{
+  if (!_autoClose)
+  {
+    _userTitle = ("<Finished>");
+    emit titleChanged();
+    return;
+  }
+  if (!_wantedClose && (exitStatus || _shellProcess->signalled()))
+  {
+    QString message;
+
+    if (_shellProcess->normalExit())
+      message.sprintf ("Session '%s' exited with status %d.", _nameTitle.toAscii().data(), exitStatus);
+    else if (_shellProcess->signalled())
+    {
+      if (_shellProcess->coreDumped())
+      {    
+
+        message.sprintf("Session '%s' exited with signal %d and dumped core.", _nameTitle.toAscii().data(), _shellProcess->exitSignal());
+      }
+      else { 
+        message.sprintf("Session '%s' exited with signal %d.", _nameTitle.toAscii().data(), _shellProcess->exitSignal());
+      }
+    }
+    else
+        message.sprintf ("Session '%s' exited unexpectedly.", _nameTitle.toAscii().data());
+
+    //FIXME: See comments in Session::monitorTimerDone()
+//    KNotification::event("Finished", message , QPixmap(),
+//                         QApplication::activeWindow(),
+//                         KNotification::CloseWhenWidgetActivated);
+  }
+  emit finished();
+}
+
+Emulation* Session::emulation() const
+{
+  return _emulation;
+}
+
+QString Session::keyBindings() const
+{
+  return _emulation->keyBindings();
+}
+
+QStringList Session::environment() const
+{
+  return _environment;
+}
+
+void Session::setEnvironment(const QStringList& environment)
+{
+    _environment = environment;
+}
+
+int Session::sessionId() const
+{
+  return _sessionId;
+}
+
+void Session::setKeyBindings(const QString &id)
+{
+  _emulation->setKeyBindings(id);
+}
+
+void Session::setTitle(TitleRole role , const QString& newTitle)
+{
+    if ( title(role) != newTitle )
+    {
+        if ( role == NameRole )
+            _nameTitle = newTitle;
+        else if ( role == DisplayedTitleRole )
+            _displayTitle = newTitle;
+
+        emit titleChanged();
+    }
+}
+
+QString Session::title(TitleRole role) const
+{
+    if ( role == NameRole )
+        return _nameTitle;
+    else if ( role == DisplayedTitleRole )
+        return _displayTitle;
+    else
+        return QString();
+}
+
+void Session::setIconName(const QString& iconName)
+{
+    if ( iconName != _iconName )
+    {
+        _iconName = iconName;
+        emit titleChanged();
+    }
+}
+
+void Session::setIconText(const QString& iconText)
+{
+  _iconText = iconText;
+  //kDebug(1211)<<"Session setIconText " <<  _iconText;
+}
+
+QString Session::iconName() const
+{
+  return _iconName;
+}
+
+QString Session::iconText() const
+{
+  return _iconText;
+}
+
+void Session::setHistoryType(const HistoryType &hType)
+{
+  _emulation->setHistory(hType);
+}
+
+const HistoryType& Session::historyType() const
+{
+  return _emulation->history();
+}
+
+void Session::clearHistory()
+{
+    _emulation->clearHistory();
+}
+
+QStringList Session::arguments() const
+{
+  return _arguments;
+}
+
+QString Session::program() const
+{
+  return _program;
+}
+
+// unused currently
+bool Session::isMonitorActivity() const { return _monitorActivity; }
+// unused currently
+bool Session::isMonitorSilence()  const { return _monitorSilence; }
+
+void Session::setMonitorActivity(bool _monitor)
+{
+  _monitorActivity=_monitor;
+  _notifiedActivity=false;
+
+  activityStateSet(NOTIFYNORMAL);
+}
+
+void Session::setMonitorSilence(bool _monitor)
+{
+  if (_monitorSilence==_monitor)
+    return;
+
+  _monitorSilence=_monitor;
+  if (_monitorSilence)
+  {
+    _monitorTimer->start(_silenceSeconds*1000);
+  }
+  else
+    _monitorTimer->stop();
+
+  activityStateSet(NOTIFYNORMAL);
+}
+
+void Session::setMonitorSilenceSeconds(int seconds)
+{
+  _silenceSeconds=seconds;
+  if (_monitorSilence) {
+    _monitorTimer->start(_silenceSeconds*1000);
+  }
+}
+
+void Session::setAddToUtmp(bool set)
+{
+  _addToUtmp = set;
+}
+
+void Session::setFlowControlEnabled(bool enabled)
+{
+  if (_flowControl == enabled)
+  	return;
+
+  _flowControl = enabled;
+
+  if (_shellProcess)  
+	_shellProcess->setXonXoff(_flowControl);
+  
+  emit flowControlEnabledChanged(enabled);
+}
+bool Session::flowControlEnabled() const
+{
+	return _flowControl;
+}
+//void Session::fireZModemDetected()
+//{
+//  if (!_zmodemBusy)
+//  {
+//    QTimer::singleShot(10, this, SIGNAL(zmodemDetected()));
+//    _zmodemBusy = true;
+//  }
+//}
+
+//void Session::cancelZModem()
+//{
+//  _shellProcess->sendData("\030\030\030\030", 4); // Abort
+//  _zmodemBusy = false;
+//}
+
+//void Session::startZModem(const QString &zmodem, const QString &dir, const QStringList &list)
+//{
+//  _zmodemBusy = true;
+//  _zmodemProc = new KProcess();
+//  _zmodemProc->setOutputChannelMode( KProcess::SeparateChannels );
+//
+//  *_zmodemProc << zmodem << "-v" << list;
+//
+//  if (!dir.isEmpty())
+//     _zmodemProc->setWorkingDirectory(dir);
+//
+//  _zmodemProc->start();
+//
+//  connect(_zmodemProc,SIGNAL (readyReadStandardOutput()),
+//          this, SLOT(zmodemReadAndSendBlock()));
+//  connect(_zmodemProc,SIGNAL (readyReadStandardError()),
+//          this, SLOT(zmodemReadStatus()));
+//  connect(_zmodemProc,SIGNAL (finished(int,QProcess::ExitStatus)),
+//          this, SLOT(zmodemFinished()));
+//
+//  disconnect( _shellProcess,SIGNAL(block_in(const char*,int)), this, SLOT(onReceiveBlock(const char*,int)) );
+//  connect( _shellProcess,SIGNAL(block_in(const char*,int)), this, SLOT(zmodemRcvBlock(const char*,int)) );
+//
+//  _zmodemProgress = new ZModemDialog(QApplication::activeWindow(), false,
+//                                    i18n("ZModem Progress"));
+//
+//  connect(_zmodemProgress, SIGNAL(user1Clicked()),
+//          this, SLOT(zmodemDone()));
+//
+//  _zmodemProgress->show();
+//}
+
+/*void Session::zmodemReadAndSendBlock()
+{
+  _zmodemProc->setReadChannel( QProcess::StandardOutput );
+  QByteArray data = _zmodemProc->readAll();
+
+  if ( data.count() == 0 )
+      return;
+
+  _shellProcess->sendData(data.constData(),data.count());
+}
+*/
+/*
+void Session::zmodemReadStatus()
+{
+  _zmodemProc->setReadChannel( QProcess::StandardError );
+  QByteArray msg = _zmodemProc->readAll();
+  while(!msg.isEmpty())
+  {
+     int i = msg.indexOf('\015');
+     int j = msg.indexOf('\012');
+     QByteArray txt;
+     if ((i != -1) && ((j == -1) || (i < j)))
+     {
+       msg = msg.mid(i+1);
+     }
+     else if (j != -1)
+     {
+       txt = msg.left(j);
+       msg = msg.mid(j+1);
+     }
+     else
+     {
+       txt = msg;
+       msg.truncate(0);
+     }
+     if (!txt.isEmpty())
+       _zmodemProgress->addProgressText(QString::fromLocal8Bit(txt));
+  }
+}
+*/
+/*
+void Session::zmodemRcvBlock(const char *data, int len)
+{
+  QByteArray ba( data, len );
+
+  _zmodemProc->write( ba );
+}
+*/
+/*
+void Session::zmodemFinished()
+{
+  if (_zmodemProc)
+  {
+    delete _zmodemProc;
+    _zmodemProc = 0;
+    _zmodemBusy = false;
+
+    disconnect( _shellProcess,SIGNAL(block_in(const char*,int)), this ,SLOT(zmodemRcvBlock(const char*,int)) );
+    connect( _shellProcess,SIGNAL(block_in(const char*,int)), this, SLOT(onReceiveBlock(const char*,int)) );
+
+    _shellProcess->sendData("\030\030\030\030", 4); // Abort
+    _shellProcess->sendData("\001\013\n", 3); // Try to get prompt back
+    _zmodemProgress->transferDone();
+  }
+}
+*/
+void Session::onReceiveBlock( const char* buf, int len )
+{
+    _emulation->receiveData( buf, len );
+    emit receivedData( QString::fromLatin1( buf, len ) );
+}
+
+QSize Session::size()
+{
+  return _emulation->imageSize();
+}
+
+void Session::setSize(const QSize& size)
+{
+  if ((size.width() <= 1) || (size.height() <= 1))
+     return;
+
+  emit resizeRequest(size);
+}
+int Session::foregroundProcessId() const
+{
+    return _shellProcess->foregroundProcessGroup();
+}
+int Session::processId() const
+{
+    return _shellProcess->pid();
+}
+
+SessionGroup::SessionGroup()
+    : _masterMode(0)
+{
+}
+SessionGroup::~SessionGroup()
+{
+    // disconnect all
+    connectAll(false);
+}
+int SessionGroup::masterMode() const { return _masterMode; }
+QList<Session*> SessionGroup::sessions() const { return _sessions.keys(); }
+bool SessionGroup::masterStatus(Session* session) const { return _sessions[session]; }
+
+void SessionGroup::addSession(Session* session)
+{
+    _sessions.insert(session,false);
+
+    QListIterator<Session*> masterIter(masters());
+
+    while ( masterIter.hasNext() )
+        connectPair(masterIter.next(),session);
+}
+void SessionGroup::removeSession(Session* session)
+{
+    setMasterStatus(session,false);
+
+    QListIterator<Session*> masterIter(masters());
+
+    while ( masterIter.hasNext() )
+        disconnectPair(masterIter.next(),session);
+
+    _sessions.remove(session);
+}
+void SessionGroup::setMasterMode(int mode)
+{
+   _masterMode = mode;
+
+   connectAll(false);
+   connectAll(true);
+}
+QList<Session*> SessionGroup::masters() const
+{
+    return _sessions.keys(true);
+}
+void SessionGroup::connectAll(bool connect)
+{
+    QListIterator<Session*> masterIter(masters());
+
+    while ( masterIter.hasNext() )
+    {
+        Session* master = masterIter.next();
+
+        QListIterator<Session*> otherIter(_sessions.keys());
+        while ( otherIter.hasNext() )
+        {
+            Session* other = otherIter.next();
+
+            if ( other != master )
+            {
+                if ( connect )
+                    connectPair(master,other);
+                else
+                    disconnectPair(master,other);
+            }
+        }
+    }
+}
+void SessionGroup::setMasterStatus(Session* session , bool master)
+{
+    bool wasMaster = _sessions[session];
+    _sessions[session] = master;
+
+    if (    !wasMaster && !master
+         || wasMaster && master )
+      return;
+
+    QListIterator<Session*> iter(_sessions.keys());
+    while ( iter.hasNext() )
+    {
+        Session* other = iter.next();
+
+        if ( other != session )
+        {
+            if ( master )
+                connectPair(session,other);
+            else
+                disconnectPair(session,other);
+        }
+    }
+}
+void SessionGroup::connectPair(Session* master , Session* other)
+{
+//    qDebug() << k_funcinfo;
+
+    if ( _masterMode & CopyInputToAll )
+    {
+        qDebug() << "Connection session " << master->nameTitle() << "to" << other->nameTitle();
+
+        connect( master->emulation() , SIGNAL(sendData(const char*,int)) , other->emulation() ,
+                 SLOT(sendString(const char*,int)) );
+    }
+}
+void SessionGroup::disconnectPair(Session* master , Session* other)
+{
+//    qDebug() << k_funcinfo;
+
+    if ( _masterMode & CopyInputToAll )
+    {
+        qDebug() << "Disconnecting session " << master->nameTitle() << "from" << other->nameTitle();
+
+        disconnect( master->emulation() , SIGNAL(sendData(const char*,int)) , other->emulation() ,
+                SLOT(sendString(const char*,int)) );
+    }
+}
+
+//#include "moc_Session.cpp"
new file mode 100644
--- /dev/null
+++ b/gui//Session.h
@@ -0,0 +1,621 @@
+/*
+    This file is part of Konsole, an X terminal.
+
+    Copyright (C) 2007 by Robert Knight <robertknight@gmail.com>
+    Copyright (C) 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
+
+    Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301  USA.
+*/
+
+#ifndef SESSION_H
+#define SESSION_H
+
+// Qt
+#include <QtCore/QStringList>
+#include <QtCore>
+#include <QWidget>
+
+// Konsole
+#include "History.h"
+
+class KProcess;
+
+namespace Konsole
+{
+
+class Emulation;
+class Pty;
+class TerminalDisplay;
+//class ZModemDialog;
+
+/**
+ * Represents a terminal session consisting of a pseudo-teletype and a terminal emulation.
+ * The pseudo-teletype (or PTY) handles I/O between the terminal process and Konsole.
+ * The terminal emulation ( Emulation and subclasses ) processes the output stream from the
+ * PTY and produces a character image which is then shown on views connected to the session.
+ *
+ * Each Session can be connected to one or more views by using the addView() method.
+ * The attached views can then display output from the program running in the terminal
+ * or send input to the program in the terminal in the form of keypresses and mouse
+ * activity.
+ */
+class Session : public QObject
+{
+Q_OBJECT
+
+public:
+  Q_PROPERTY(QString name READ nameTitle)
+  Q_PROPERTY(int processId READ processId)
+  Q_PROPERTY(QString keyBindings READ keyBindings WRITE setKeyBindings)
+  Q_PROPERTY(QSize size READ size WRITE setSize)
+
+  /**
+   * Constructs a new session.
+   *
+   * To start the terminal process, call the run() method,
+   * after specifying the program and arguments
+   * using setProgram() and setArguments()
+   *
+   * If no program or arguments are specified explicitly, the Session
+   * falls back to using the program specified in the SHELL environment
+   * variable.
+   */
+  Session();
+  ~Session();
+
+  /**
+   * Returns true if the session is currently running.  This will be true
+   * after run() has been called successfully.
+   */
+  bool isRunning() const;
+
+  /**
+   * Sets the profile associated with this session.
+   *
+   * @param profileKey A key which can be used to obtain the current
+   * profile settings from the SessionManager
+   */
+  void setProfileKey(const QString& profileKey);
+  /**
+   * Returns the profile key associated with this session.
+   * This can be passed to the SessionManager to obtain the current
+   * profile settings.
+   */
+  QString profileKey() const;
+
+  /**
+   * Adds a new view for this session.
+   *
+   * The viewing widget will display the output from the terminal and
+   * input from the viewing widget (key presses, mouse activity etc.)
+   * will be sent to the terminal.
+   *
+   * Views can be removed using removeView().  The session is automatically
+   * closed when the last view is removed.
+   */
+  void addView(TerminalDisplay* widget);
+  /**
+   * Removes a view from this session.  When the last view is removed,
+   * the session will be closed automatically.
+   *
+   * @p widget will no longer display output from or send input
+   * to the terminal
+   */
+  void removeView(TerminalDisplay* widget);
+
+  /**
+   * Returns the views connected to this session
+   */
+  QList<TerminalDisplay*> views() const;
+
+  /**
+   * Returns the terminal emulation instance being used to encode / decode
+   * characters to / from the process.
+   */
+  Emulation*  emulation() const;
+
+  /**
+   * Returns the environment of this session as a list of strings like
+   * VARIABLE=VALUE
+   */
+  QStringList environment() const;
+  /**
+   * Sets the environment for this session.
+   * @p environment should be a list of strings like
+   * VARIABLE=VALUE
+   */
+  void setEnvironment(const QStringList& environment);
+
+  /** Returns the unique ID for this session. */
+  int sessionId() const;
+
+  /**
+   * Return the session title set by the user (ie. the program running
+   * in the terminal), or an empty string if the user has not set a custom title
+   */
+  QString userTitle() const;
+
+  /**
+   * This enum describes the contexts for which separate
+   * tab title formats may be specified.
+   */
+  enum TabTitleContext
+  {
+    /** Default tab title format */
+    LocalTabTitle,
+    /**
+     * Tab title format used session currently contains
+     * a connection to a remote computer (via SSH)
+     */
+    RemoteTabTitle
+  };
+  /**
+   * Sets the format used by this session for tab titles.
+   *
+   * @param context The context whoose format should be set.
+   * @param format The tab title format.  This may be a mixture
+   * of plain text and dynamic elements denoted by a '%' character
+   * followed by a letter.  (eg. %d for directory).  The dynamic
+   * elements available depend on the @p context
+   */
+  void setTabTitleFormat(TabTitleContext context , const QString& format);
+  /** Returns the format used by this session for tab titles. */
+  QString tabTitleFormat(TabTitleContext context) const;
+
+
+  /** Returns the arguments passed to the shell process when run() is called. */
+  QStringList arguments() const;
+  /** Returns the program name of the shell process started when run() is called. */
+  QString program() const;
+
+  /**
+   * Sets the command line arguments which the session's program will be passed when
+   * run() is called.
+   */
+  void setArguments(const QStringList& arguments);
+  /** Sets the program to be executed when run() is called. */
+  void setProgram(const QString& program);
+
+  /** Returns the session's current working directory. */
+  QString initialWorkingDirectory() { return _initialWorkingDir; }
+
+  /**
+   * Sets the initial working directory for the session when it is run
+   * This has no effect once the session has been started.
+   */
+  void setInitialWorkingDirectory( const QString& dir );
+
+  /**
+   * Sets the type of history store used by this session.
+   * Lines of output produced by the terminal are added
+   * to the history store.  The type of history store
+   * used affects the number of lines which can be
+   * remembered before they are lost and the storage
+   * (in memory, on-disk etc.) used.
+   */
+  void setHistoryType(const HistoryType& type);
+  /**
+   * Returns the type of history store used by this session.
+   */
+  const HistoryType& historyType() const;
+  /**
+   * Clears the history store used by this session.
+   */
+  void clearHistory();
+
+  /**
+   * Enables monitoring for activity in the session.
+   * This will cause notifySessionState() to be emitted
+   * with the NOTIFYACTIVITY state flag when output is
+   * received from the terminal.
+   */
+  void setMonitorActivity(bool);
+  /** Returns true if monitoring for activity is enabled. */
+  bool isMonitorActivity() const;
+
+  /**
+   * Enables monitoring for silence in the session.
+   * This will cause notifySessionState() to be emitted
+   * with the NOTIFYSILENCE state flag when output is not
+   * received from the terminal for a certain period of
+   * time, specified with setMonitorSilenceSeconds()
+   */
+  void setMonitorSilence(bool);
+  /**
+   * Returns true if monitoring for inactivity (silence)
+   * in the session is enabled.
+   */
+  bool isMonitorSilence()  const;
+  /** See setMonitorSilence() */
+  void setMonitorSilenceSeconds(int seconds);
+
+  /**
+   * Sets the key bindings used by this session.  The bindings
+   * specify how input key sequences are translated into
+   * the character stream which is sent to the terminal.
+   *
+   * @param id The name of the key bindings to use.  The
+   * names of available key bindings can be determined using the
+   * KeyboardTranslatorManager class.
+   */
+  void setKeyBindings(const QString& id);
+  /** Returns the name of the key bindings used by this session. */
+  QString keyBindings() const;
+
+  /**
+   * This enum describes the available title roles.
+   */
+  enum TitleRole
+  {
+      /** The name of the session. */
+      NameRole,
+      /** The title of the session which is displayed in tabs etc. */
+      DisplayedTitleRole
+  };
+
+  /** Sets the session's title for the specified @p role to @p title. */
+  void setTitle(TitleRole role , const QString& title);
+  /** Returns the session's title for the specified @p role. */
+  QString title(TitleRole role) const;
+  /** Convenience method used to read the name property.  Returns title(Session::NameRole). */
+  QString nameTitle() const { return title(Session::NameRole); }
+
+  /** Sets the name of the icon associated with this session. */
+  void setIconName(const QString& iconName);
+  /** Returns the name of the icon associated with this session. */
+  QString iconName() const;
+
+  /** Sets the text of the icon associated with this session. */
+  void setIconText(const QString& iconText);
+  /** Returns the text of the icon associated with this session. */
+  QString iconText() const;
+
+  /** Specifies whether a utmp entry should be created for the pty used by this session. */
+  void setAddToUtmp(bool);
+
+  /** Sends the specified @p signal to the terminal process. */
+  bool sendSignal(int signal);
+
+  /**
+   * Specifies whether to close the session automatically when the terminal
+   * process terminates.
+   */
+  void setAutoClose(bool b) { _autoClose = b; }
+
+  /**
+   * Sets whether flow control is enabled for this terminal
+   * session.
+   */
+  void setFlowControlEnabled(bool enabled);
+
+  /** Returns whether flow control is enabled for this terminal session. */
+  bool flowControlEnabled() const;
+
+  /**
+   * Sends @p text to the current foreground terminal program.
+   */
+  void sendText(const QString& text) const;
+
+  /**
+   * Returns the process id of the terminal process.
+   * This is the id used by the system API to refer to the process.
+   */
+  int processId() const;
+
+  /**
+   * Returns the process id of the terminal's foreground process.
+   * This is initially the same as processId() but can change
+   * as the user starts other programs inside the terminal.
+   */
+  int foregroundProcessId() const;
+
+  /** Returns the terminal session's window size in lines and columns. */
+  QSize size();
+  /**
+   * Emits a request to resize the session to accommodate
+   * the specified window size.
+   *
+   * @param size The size in lines and columns to request.
+   */
+  void setSize(const QSize& size);
+
+  /** Sets the text codec used by this session's terminal emulation. */
+  void setCodec(QTextCodec* codec);
+
+  /**
+   * Sets whether the session has a dark background or not.  The session
+   * uses this information to set the COLORFGBG variable in the process's
+   * environment, which allows the programs running in the terminal to determine
+   * whether the background is light or dark and use appropriate colors by default.
+   *
+   * This has no effect once the session is running.
+   */
+  void setDarkBackground(bool darkBackground);
+  /**
+   * Returns true if the session has a dark background.
+   * See setDarkBackground()
+   */
+  bool hasDarkBackground() const;
+
+  /**
+   * Attempts to get the shell program to redraw the current display area.
+   * This can be used after clearing the screen, for example, to get the
+   * shell to redraw the prompt line.
+   */
+  void refresh();
+
+//  void startZModem(const QString &rz, const QString &dir, const QStringList &list);
+//  void cancelZModem();
+//  bool isZModemBusy() { return _zmodemBusy; }
+
+public slots:
+
+  /**
+   * Starts the terminal session.
+   *
+   * This creates the terminal process and connects the teletype to it.
+   */
+  void run();
+
+  /**
+   * Closes the terminal session.  This sends a hangup signal
+   * (SIGHUP) to the terminal process and causes the done(Session*)
+   * signal to be emitted.
+   */
+  void close();
+
+  /**
+   * Changes the session title or other customizable aspects of the terminal
+   * emulation display. For a list of what may be changed see the
+   * Emulation::titleChanged() signal.
+   */
+  void setUserTitle( int, const QString &caption );
+
+signals:
+
+  /** Emitted when the terminal process starts. */
+  void started();
+
+  /**
+   * Emitted when the terminal process exits.
+   */
+  void finished();
+
+  /**
+   * Emitted when output is received from the terminal process.
+   */
+  void receivedData( const QString& text );
+
+  /** Emitted when the session's title has changed. */
+  void titleChanged();
+
+  /** Emitted when the session's profile has changed. */
+  void profileChanged(const QString& profile);
+
+  /**
+   * Emitted when the activity state of this session changes.
+   *
+   * @param state The new state of the session.  This may be one
+   * of NOTIFYNORMAL, NOTIFYSILENCE or NOTIFYACTIVITY
+   */
+  void stateChanged(int state);
+
+  /** Emitted when a bell event occurs in the session. */
+  void bellRequest( const QString& message );
+
+  /**
+   * Requests that the color the text for any tabs associated with
+   * this session should be changed;
+   *
+   * TODO: Document what the parameter does
+   */
+  void changeTabTextColorRequest(int);
+
+  /**
+   * Requests that the background color of views on this session
+   * should be changed.
+   */
+  void changeBackgroundColorRequest(const QColor&);
+
+  /** TODO: Document me. */
+  void openUrlRequest(const QString& url);
+
+  /** TODO: Document me. */
+//  void zmodemDetected();
+
+  /**
+   * Emitted when the terminal process requests a change
+   * in the size of the terminal window.
+   *
+   * @param size The requested window size in terms of lines and columns.
+   */
+  void resizeRequest(const QSize& size);
+
+  /**
+   * Emitted when a profile change command is received from the terminal.
+   *
+   * @param text The text of the command.  This is a string of the form
+   * "PropertyName=Value;PropertyName=Value ..."
+   */
+  void profileChangeCommandReceived(const QString& text);
+
+ /**
+  * Emitted when the flow control state changes.
+  *
+  * @param enabled True if flow control is enabled or false otherwise.
+  */
+  void flowControlEnabledChanged(bool enabled);
+
+private slots:
+  void done(int);
+
+//  void fireZModemDetected();
+
+  void onReceiveBlock( const char* buffer, int len );
+  void monitorTimerDone();
+
+  void onViewSizeChange(int height, int width);
+  void onEmulationSizeChange(int lines , int columns);
+
+  void activityStateSet(int);
+
+  //automatically detach views from sessions when view is destroyed
+  void viewDestroyed(QObject* view);
+
+//  void zmodemReadStatus();
+//  void zmodemReadAndSendBlock();
+//  void zmodemRcvBlock(const char *data, int len);
+//  void zmodemFinished();
+
+private:
+
+  void updateTerminalSize();
+  WId windowId() const;
+
+  int            _uniqueIdentifier;
+
+  Pty*          _shellProcess;
+  Emulation*    _emulation;
+
+  QList<TerminalDisplay*> _views;
+
+  bool           _monitorActivity;
+  bool           _monitorSilence;
+  bool           _notifiedActivity;
+  bool           _masterMode;
+  bool           _autoClose;
+  bool           _wantedClose;
+  QTimer*        _monitorTimer;
+
+  int            _silenceSeconds;
+
+  QString        _nameTitle;
+  QString        _displayTitle;
+  QString        _userTitle;
+
+  QString        _localTabTitleFormat;
+  QString        _remoteTabTitleFormat;
+
+  QString        _iconName;
+  QString        _iconText; // as set by: echo -en '\033]1;IconText\007
+  bool           _addToUtmp;
+  bool           _flowControl;
+  bool           _fullScripting;
+
+  QString        _program;
+  QStringList    _arguments;
+
+  QStringList    _environment;
+  int            _sessionId;
+
+  QString        _initialWorkingDir;
+
+  // ZModem
+//  bool           _zmodemBusy;
+//  KProcess*      _zmodemProc;
+//  ZModemDialog*  _zmodemProgress;
+
+  // Color/Font Changes by ESC Sequences
+
+  QColor         _modifiedBackground; // as set by: echo -en '\033]11;Color\007
+
+  QString        _profileKey;
+
+  bool _hasDarkBackground;
+
+  static int lastSessionId;
+
+};
+
+/**
+ * Provides a group of sessions which is divided into master and slave sessions.
+ * Activity in master sessions can be propagated to all sessions within the group.
+ * The type of activity which is propagated and method of propagation is controlled
+ * by the masterMode() flags.
+ */
+class SessionGroup : public QObject
+{
+Q_OBJECT
+
+public:
+    /** Constructs an empty session group. */
+    SessionGroup();
+    /** Destroys the session group and removes all connections between master and slave sessions. */
+    ~SessionGroup();
+
+    /** Adds a session to the group. */
+    void addSession( Session* session );
+    /** Removes a session from the group. */
+    void removeSession( Session* session );
+
+    /** Returns the list of sessions currently in the group. */
+    QList<Session*> sessions() const;
+
+    /**
+     * Sets whether a particular session is a master within the group.
+     * Changes or activity in the group's master sessions may be propagated
+     * to all the sessions in the group, depending on the current masterMode()
+     *
+     * @param session The session whoose master status should be changed.
+     * @param master True to make this session a master or false otherwise
+     */
+    void setMasterStatus( Session* session , bool master );
+    /** Returns the master status of a session.  See setMasterStatus() */
+    bool masterStatus( Session* session ) const;
+
+    /**
+     * This enum describes the options for propagating certain activity or
+     * changes in the group's master sessions to all sessions in the group.
+     */
+    enum MasterMode
+    {
+        /**
+         * Any input key presses in the master sessions are sent to all
+         * sessions in the group.
+         */
+        CopyInputToAll = 1
+    };
+
+    /**
+     * Specifies which activity in the group's master sessions is propagated
+     * to all sessions in the group.
+     *
+     * @param mode A bitwise OR of MasterMode flags.
+     */
+    void setMasterMode( int mode );
+    /**
+     * Returns a bitwise OR of the active MasterMode flags for this group.
+     * See setMasterMode()
+     */
+    int masterMode() const;
+
+private:
+    void connectPair(Session* master , Session* other);
+    void disconnectPair(Session* master , Session* other);
+    void connectAll(bool connect);
+    QList<Session*> masters() const;
+
+    // maps sessions to their master status
+    QHash<Session*,bool> _sessions;
+
+    int _masterMode;
+};
+
+}
+
+#endif
new file mode 100644
--- /dev/null
+++ b/gui//ShellCommand.cpp
@@ -0,0 +1,168 @@
+/*
+    Copyright (C) 2007 by Robert Knight <robertknight@gmail.com>
+
+    Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301  USA.
+*/
+
+// Own
+#include "ShellCommand.h"
+
+//some versions of gcc(4.3) require explicit include
+#include <cstdlib>
+
+
+using namespace Konsole;
+
+// expands environment variables in 'text'
+// function copied from kdelibs/kio/kio/kurlcompletion.cpp
+static bool expandEnv(QString& text);
+
+ShellCommand::ShellCommand(const QString& fullCommand)
+{
+    bool inQuotes = false;
+
+    QString builder;
+
+    for ( int i = 0 ; i < fullCommand.count() ; i++ )
+    {
+        QChar ch = fullCommand[i];
+
+        const bool isLastChar = ( i == fullCommand.count() - 1 );
+        const bool isQuote = ( ch == '\'' || ch == '\"' );
+
+        if ( !isLastChar && isQuote )
+            inQuotes = !inQuotes;
+        else
+        { 
+            if ( (!ch.isSpace() || inQuotes) && !isQuote )
+                builder.append(ch);
+
+            if ( (ch.isSpace() && !inQuotes) || ( i == fullCommand.count()-1 ) )
+            {
+                _arguments << builder;      
+                builder.clear(); 
+            }
+        }
+    }
+}
+ShellCommand::ShellCommand(const QString& command , const QStringList& arguments)
+{
+    _arguments = arguments;
+    
+    if ( !_arguments.isEmpty() )
+        _arguments[0] == command;
+}
+QString ShellCommand::fullCommand() const
+{
+    return _arguments.join(QChar(' '));
+}
+QString ShellCommand::command() const
+{
+    if ( !_arguments.isEmpty() )
+        return _arguments[0];
+    else
+        return QString();
+}
+QStringList ShellCommand::arguments() const
+{
+    return _arguments;
+}
+bool ShellCommand::isRootCommand() const
+{
+    Q_ASSERT(0); // not implemented yet
+    return false;
+}
+bool ShellCommand::isAvailable() const
+{
+    Q_ASSERT(0); // not implemented yet
+    return false; 
+}
+QStringList ShellCommand::expand(const QStringList& items)
+{
+    QStringList result;
+
+    foreach( QString item , items )
+        result << expand(item);
+
+    return result;
+}
+QString ShellCommand::expand(const QString& text)
+{
+    QString result = text;
+    expandEnv(result);
+    return result;
+}
+
+/*
+ * expandEnv
+ *
+ * Expand environment variables in text. Escaped '$' characters are ignored.
+ * Return true if any variables were expanded
+ */
+static bool expandEnv( QString &text )
+{
+	// Find all environment variables beginning with '$'
+	//
+	int pos = 0;
+
+	bool expanded = false;
+
+	while ( (pos = text.indexOf(QLatin1Char('$'), pos)) != -1 ) {
+
+		// Skip escaped '$'
+		//
+		if ( pos > 0 && text.at(pos-1) == QLatin1Char('\\') ) {
+			pos++;
+		}
+		// Variable found => expand
+		//
+		else {
+			// Find the end of the variable = next '/' or ' '
+			//
+			int pos2 = text.indexOf( QLatin1Char(' '), pos+1 );
+			int pos_tmp = text.indexOf( QLatin1Char('/'), pos+1 );
+
+			if ( pos2 == -1 || (pos_tmp != -1 && pos_tmp < pos2) )
+				pos2 = pos_tmp;
+
+			if ( pos2 == -1 )
+				pos2 = text.length();
+
+			// Replace if the variable is terminated by '/' or ' '
+			// and defined
+			//
+			if ( pos2 >= 0 ) {
+				int len	= pos2 - pos;
+				QString key	= text.mid( pos+1, len-1);
+				QString value =
+					QString::fromLocal8Bit( ::getenv(key.toLocal8Bit()) );
+
+				if ( !value.isEmpty() ) {
+					expanded = true;
+					text.replace( pos, len, value );
+					pos = pos + value.length();
+				}
+				else {
+					pos = pos2;
+				}
+			}
+		}
+	}
+
+	return expanded;
+}
new file mode 100644
--- /dev/null
+++ b/gui//ShellCommand.h
@@ -0,0 +1,94 @@
+/*
+    Copyright (C) 2007 by Robert Knight <robertknight@gmail.com>
+
+    Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301  USA.
+*/
+
+#ifndef SHELLCOMMAND_H
+#define SHELLCOMMAND_H
+
+// Qt
+#include <QtCore/QStringList>
+
+namespace Konsole
+{
+
+/** 
+ * A class to parse and extract information about shell commands. 
+ *
+ * ShellCommand can be used to:
+ *
+ * <ul>
+ *      <li>Take a command-line (eg "/bin/sh -c /path/to/my/script") and split it
+ *          into its component parts (eg. the command "/bin/sh" and the arguments
+ *          "-c","/path/to/my/script")
+ *      </li>
+ *      <li>Take a command and a list of arguments and combine them to 
+ *          form a complete command line.
+ *      </li>
+ *      <li>Determine whether the binary specified by a command exists in the
+ *          user's PATH.
+ *      </li>
+ *      <li>Determine whether a command-line specifies the execution of
+ *          another command as the root user using su/sudo etc.
+ *      </li>
+ * </ul> 
+ */
+class ShellCommand
+{
+public:
+    /**
+     * Constructs a ShellCommand from a command line.
+     *
+     * @param fullCommand The command line to parse.  
+     */
+    ShellCommand(const QString& fullCommand);
+    /**
+     * Constructs a ShellCommand with the specified @p command and @p arguments.
+     */
+    ShellCommand(const QString& command , const QStringList& arguments);
+
+    /** Returns the command. */
+    QString command() const;
+    /** Returns the arguments. */
+    QStringList arguments() const;
+
+    /** 
+     * Returns the full command line. 
+     */
+    QString fullCommand() const;
+
+    /** Returns true if this is a root command. */
+    bool isRootCommand() const;
+    /** Returns true if the program specified by @p command() exists. */
+    bool isAvailable() const;
+
+    /** Expands environment variables in @p text .*/
+    static QString expand(const QString& text);
+
+    /** Expands environment variables in each string in @p list. */
+    static QStringList expand(const QStringList& items);
+
+private:
+    QStringList _arguments;    
+};
+
+}
+
+#endif // SHELLCOMMAND_H
+
new file mode 100644
--- /dev/null
+++ b/gui//TODO
@@ -0,0 +1,10 @@
+Global
+ - provide more compatibility for vttest
+
+Package
+ - migrate to autotools if needed
+
+Source
+ - provide more options for customization
+ - clean unused code
+ - add some QT3 support features if needed
new file mode 100644
--- /dev/null
+++ b/gui//TerminalCharacterDecoder.cpp
@@ -0,0 +1,227 @@
+/*
+    This file is part of Konsole, an X terminal.
+    
+    Copyright (C) 2006 by Robert Knight <robertknight@gmail.com>
+    
+    Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301  USA.
+*/
+
+// Own
+#include "TerminalCharacterDecoder.h"
+
+// Qt
+#include <QtCore/QTextStream>
+
+
+using namespace Konsole;
+
+PlainTextDecoder::PlainTextDecoder()
+ : _output(0)
+ , _includeTrailingWhitespace(true)
+{
+
+}
+void PlainTextDecoder::setTrailingWhitespace(bool enable)
+{
+    _includeTrailingWhitespace = enable;
+}
+bool PlainTextDecoder::trailingWhitespace() const
+{
+    return _includeTrailingWhitespace;
+}
+void PlainTextDecoder::begin(QTextStream* output)
+{
+   _output = output; 
+}
+void PlainTextDecoder::end()
+{
+    _output = 0;
+}
+void PlainTextDecoder::decodeLine(const Character* const characters, int count, LineProperty /*properties*/
+							 )
+{
+    Q_ASSERT( _output );
+
+	//TODO should we ignore or respect the LINE_WRAPPED line property?
+
+	//note:  we build up a QString and send it to the text stream rather writing into the text
+	//stream a character at a time because it is more efficient.
+	//(since QTextStream always deals with QStrings internally anyway)
+	QString plainText;
+	plainText.reserve(count);
+   
+    int outputCount = count;
+
+    // if inclusion of trailing whitespace is disabled then find the end of the
+    // line
+    if ( !_includeTrailingWhitespace )
+    {
+        for (int i = count-1 ; i >= 0 ; i--)
+        {
+            if ( characters[i].character != ' '  )
+                break;
+            else
+                outputCount--;
+        }
+    }
+
+	for (int i=0;i<outputCount;i++)
+	{
+		plainText.append( QChar(characters[i].character) );
+	}
+
+	*_output << plainText;
+}
+
+HTMLDecoder::HTMLDecoder() :
+        _output(0)
+	   ,_colorTable(base_color_table)
+       ,_innerSpanOpen(false)
+       ,_lastRendition(DEFAULT_RENDITION)
+{
+	
+}
+
+void HTMLDecoder::begin(QTextStream* output)
+{
+    _output = output;
+
+    QString text;
+
+	//open monospace span
+    openSpan(text,"font-family:monospace");
+
+    *output << text;
+}
+
+void HTMLDecoder::end()
+{
+    Q_ASSERT( _output );
+
+    QString text;
+
+    closeSpan(text);
+
+    *_output << text;
+
+    _output = 0;
+
+}
+
+//TODO: Support for LineProperty (mainly double width , double height)
+void HTMLDecoder::decodeLine(const Character* const characters, int count, LineProperty /*properties*/
+							)
+{
+    Q_ASSERT( _output );
+
+	QString text;
+
+	int spaceCount = 0;
+		
+	for (int i=0;i<count;i++)
+	{
+		QChar ch(characters[i].character);
+
+		//check if appearance of character is different from previous char
+		if ( characters[i].rendition != _lastRendition  ||
+		     characters[i].foregroundColor != _lastForeColor  ||
+			 characters[i].backgroundColor != _lastBackColor )
+		{
+			if ( _innerSpanOpen )
+					closeSpan(text);
+
+			_lastRendition = characters[i].rendition;
+			_lastForeColor = characters[i].foregroundColor;
+			_lastBackColor = characters[i].backgroundColor;
+			
+			//build up style string
+			QString style;
+
+			if ( _lastRendition & RE_BOLD ||
+                             (_colorTable && characters[i].isBold(_colorTable)) )
+					style.append("font-weight:bold;");
+
+
+			if ( _lastRendition & RE_UNDERLINE )
+					style.append("font-decoration:underline;");
+		
+			//colours - a colour table must have been defined first
+			if ( _colorTable )	
+			{
+				style.append( QString("color:%1;").arg(_lastForeColor.color(_colorTable).name() ) );
+
+				if (!characters[i].isTransparent(_colorTable))
+				{
+					style.append( QString("background-color:%1;").arg(_lastBackColor.color(_colorTable).name() ) );
+				}
+			}
+		
+			//open the span with the current style	
+			openSpan(text,style);
+			_innerSpanOpen = true;
+		}
+
+		//handle whitespace
+		if (ch.isSpace())
+			spaceCount++;
+		else
+			spaceCount = 0;
+		
+
+		//output current character
+		if (spaceCount < 2)
+		{
+			//escape HTML tag characters and just display others as they are
+			if ( ch == '<' )
+				text.append("&lt;");
+			else if (ch == '>')
+					text.append("&gt;");
+			else	
+					text.append(ch);
+		}
+		else
+		{
+			text.append("&nbsp;"); //HTML truncates multiple spaces, so use a space marker instead
+		}
+		
+	}
+
+	//close any remaining open inner spans
+	if ( _innerSpanOpen )
+		closeSpan(text);
+
+	//start new line
+	text.append("<br>");
+	
+	*_output << text;
+}
+
+void HTMLDecoder::openSpan(QString& text , const QString& style)
+{
+	text.append( QString("<span style=\"%1\">").arg(style) );
+}
+
+void HTMLDecoder::closeSpan(QString& text)
+{
+	text.append("</span>");
+}
+
+void HTMLDecoder::setColorTable(const ColorEntry* table)
+{
+	_colorTable = table;
+}
new file mode 100644
--- /dev/null
+++ b/gui//TerminalCharacterDecoder.h
@@ -0,0 +1,139 @@
+/*
+    This file is part of Konsole, an X terminal.
+    
+    Copyright (C) 2006-7 by Robert Knight <robertknight@gmail.com>
+    
+    Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301  USA.
+*/
+
+#ifndef TERMINAL_CHARACTER_DECODER_H
+#define TERMINAL_CHARACTER_DECODER_H
+
+#include "Character.h"
+
+class QTextStream;
+
+namespace Konsole
+{
+
+/**
+ * Base class for terminal character decoders
+ *
+ * The decoder converts lines of terminal characters which consist of a unicode character, foreground
+ * and background colours and other appearance-related properties into text strings.
+ *
+ * Derived classes may produce either plain text with no other colour or appearance information, or
+ * they may produce text which incorporates these additional properties. 
+ */
+class TerminalCharacterDecoder
+{
+public:
+	virtual ~TerminalCharacterDecoder() {}
+
+    /** Begin decoding characters.  The resulting text is appended to @p output. */
+    virtual void begin(QTextStream* output) = 0;
+    /** End decoding. */
+    virtual void end() = 0;
+
+	/**
+	 * Converts a line of terminal characters with associated properties into a text string
+	 * and writes the string into an output QTextStream.
+	 *
+	 * @param characters An array of characters of length @p count.
+	 * @param properties Additional properties which affect all characters in the line
+	 * @param output The output stream which receives the decoded text
+	 */
+	virtual void decodeLine(const Character* const characters, 
+							int count,
+							LineProperty properties) = 0; 
+};
+
+/**
+ * A terminal character decoder which produces plain text, ignoring colours and other appearance-related
+ * properties of the original characters.
+ */
+class PlainTextDecoder : public TerminalCharacterDecoder
+{
+public:
+	PlainTextDecoder(); 
+
+    /** 
+     * Set whether trailing whitespace at the end of lines should be included 
+     * in the output.
+     * Defaults to true.
+     */
+    void setTrailingWhitespace(bool enable);
+    /**
+     * Returns whether trailing whitespace at the end of lines is included
+     * in the output.
+     */
+    bool trailingWhitespace() const;
+
+    virtual void begin(QTextStream* output);
+    virtual void end();
+
+	virtual void decodeLine(const Character* const characters,
+							int count,
+							LineProperty properties);	
+
+    
+private:
+    QTextStream* _output;
+    bool _includeTrailingWhitespace;
+};
+
+/**
+ * A terminal character decoder which produces pretty HTML markup
+ */
+class HTMLDecoder : public TerminalCharacterDecoder
+{
+public:
+	/** 
+	 * Constructs an HTML decoder using a default black-on-white color scheme.
+	 */
+	HTMLDecoder();
+
+	/**
+	 * Sets the colour table which the decoder uses to produce the HTML colour codes in its
+	 * output
+	 */
+	void setColorTable( const ColorEntry* table );
+		
+	virtual void decodeLine(const Character* const characters,
+							int count,
+							LineProperty properties);
+
+    virtual void begin(QTextStream* output);
+    virtual void end();
+
+private:
+	void openSpan(QString& text , const QString& style);
+	void closeSpan(QString& text);
+
+    QTextStream* _output;
+	const ColorEntry* _colorTable;
+    bool _innerSpanOpen; 
+	quint8 _lastRendition;
+	CharacterColor _lastForeColor;
+	CharacterColor _lastBackColor;
+
+};
+
+}
+
+#endif
new file mode 100644
--- /dev/null
+++ b/gui//TerminalDisplay.cpp
@@ -0,0 +1,2724 @@
+/*
+    This file is part of Konsole, a terminal emulator for KDE.
+    
+    Copyright (C) 2006-7 by Robert Knight <robertknight@gmail.com>
+    Copyright (C) 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
+    
+    Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301  USA.
+*/
+
+// Own
+#include "TerminalDisplay.h"
+
+// Qt
+#include <QtGui/QApplication>
+#include <QtGui/QBoxLayout>
+#include <QtGui/QClipboard>
+#include <QtGui/QKeyEvent>
+#include <QtCore/QEvent>
+#include <QtCore/QTime>
+#include <QtCore/QFile>
+#include <QtGui/QGridLayout>
+#include <QtGui/QLabel>
+#include <QtGui/QLayout>
+#include <QtGui/QPainter>
+#include <QtGui/QPixmap>
+#include <QtGui/QScrollBar>
+#include <QtGui/QStyle>
+#include <QtCore>
+#include <QtGui>
+
+#include "Filter.h"
+#include "konsole_wcwidth.h"
+#include "ScreenWindow.h"
+#include "TerminalCharacterDecoder.h"
+#include "ColorTables.h"
+
+using namespace Konsole;
+
+#ifndef loc
+#define loc(X,Y) ((Y)*_columns+(X))
+#endif
+
+#define yMouseScroll 1
+
+#define REPCHAR   "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
+                  "abcdefgjijklmnopqrstuvwxyz" \
+                  "0123456789./+@"
+
+// scroll increment used when dragging selection at top/bottom of window.
+
+// static
+bool TerminalDisplay::_antialiasText = true;
+bool TerminalDisplay::HAVE_TRANSPARENCY = false;
+
+/* ------------------------------------------------------------------------- */
+/*                                                                           */
+/*                                Colors                                     */
+/*                                                                           */
+/* ------------------------------------------------------------------------- */
+
+/* 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
+*/
+
+ScreenWindow* TerminalDisplay::screenWindow() const
+{
+    return _screenWindow;
+}
+void TerminalDisplay::setScreenWindow(ScreenWindow* window)
+{
+    // disconnect existing screen window if any
+    if ( _screenWindow )
+    {
+        disconnect( _screenWindow , 0 , this , 0 );
+    }
+
+    _screenWindow = window;
+
+    if ( window )
+    {
+//#warning "The order here is not specified - does it matter whether updateImage or updateLineProperties comes first?"
+        connect( _screenWindow , SIGNAL(outputChanged()) , this , SLOT(updateLineProperties()) );
+        connect( _screenWindow , SIGNAL(outputChanged()) , this , SLOT(updateImage()) );
+	window->setWindowLines(_lines);
+    }
+}
+
+const ColorEntry* TerminalDisplay::colorTable() const
+{
+  return _colorTable;
+}
+
+void TerminalDisplay::setColorTable(const ColorEntry table[])
+{
+  for (int i = 0; i < TABLE_COLORS; i++)
+      _colorTable[i] = table[i];
+
+  QPalette p = palette();
+  p.setColor( backgroundRole(), _colorTable[DEFAULT_BACK_COLOR].color );
+  setPalette( p );
+
+  // Avoid propagating the palette change to the scroll bar 
+  _scrollBar->setPalette( QApplication::palette() );  
+
+  update();
+}
+
+/* ------------------------------------------------------------------------- */
+/*                                                                           */
+/*                                   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.
+*/
+
+static inline bool isLineChar(quint16 c) { return ((c & 0xFF80) == 0x2500);}
+static inline bool isLineCharString(const QString& string)
+{
+		return (string.length() > 0) && (isLineChar(string.at(0).unicode()));
+}
+						
+
+// assert for i in [0..31] : vt100extended(vt100_graphics[i]) == i.
+
+unsigned short Konsole::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
+};
+
+void TerminalDisplay::fontChange(const QFont&)
+{
+  QFontMetrics fm(font());
+  _fontHeight = fm.height() + _lineSpacing;
+
+
+  // waba TerminalDisplay 1.123:
+  // "Base character width on widest ASCII character. This prevents too wide
+  //  characters in the presence of double wide (e.g. Japanese) characters."
+  // Get the width from representative normal width characters
+  _fontWidth = qRound((double)fm.width(REPCHAR)/(double)strlen(REPCHAR));
+
+  _fixedFont = true;
+
+  int fw = fm.width(REPCHAR[0]);
+  for(unsigned int i=1; i< strlen(REPCHAR); i++)
+  {
+    if (fw != fm.width(REPCHAR[i]))
+    {
+      _fixedFont = false;
+      break;
+    }
+  }
+
+  if (_fontWidth < 1)
+    _fontWidth=1;
+
+  _fontAscent = fm.ascent();
+
+  emit changedFontMetricSignal( _fontHeight, _fontWidth );
+  propagateSize();
+  update();
+}
+
+void TerminalDisplay::setVTFont(const QFont& f)
+{
+  QFont font = f;
+
+  QFontMetrics metrics(font);
+
+  if ( metrics.height() < height() && metrics.maxWidth() < width() )
+  {
+    // hint that text should be drawn without anti-aliasing.  
+    // depending on the user's font configuration, this may not be respected
+    if (!_antialiasText)
+        font.setStyleStrategy( QFont::NoAntialias );
+ 
+    // experimental optimization.  Konsole assumes that the terminal is using a 
+    // mono-spaced font, in which case kerning information should have an effect.
+    // Disabling kerning saves some computation when rendering text. 
+    font.setKerning(false);
+
+    QWidget::setFont(font);
+    fontChange(font);
+  }
+}
+
+void TerminalDisplay::setFont(const QFont &)
+{
+  // ignore font change request if not coming from konsole itself
+}
+
+/* ------------------------------------------------------------------------- */
+/*                                                                           */
+/*                         Constructor / Destructor                          */
+/*                                                                           */
+/* ------------------------------------------------------------------------- */
+
+TerminalDisplay::TerminalDisplay(QWidget *parent)
+:QWidget(parent)
+,_screenWindow(0)
+,_allowBell(true)
+,_gridLayout(0)
+,_fontHeight(1)
+,_fontWidth(1)
+,_fontAscent(1)
+,_lines(1)
+,_columns(1)
+,_usedLines(1)
+,_usedColumns(1)
+,_contentHeight(1)
+,_contentWidth(1)
+,_image(0)
+,_randomSeed(0)
+,_resizing(false)
+,_terminalSizeHint(false)
+,_terminalSizeStartup(true)
+,_bidiEnabled(false)
+,_actSel(0)
+,_wordSelectionMode(false)
+,_lineSelectionMode(false)
+,_preserveLineBreaks(false)
+,_columnSelectionMode(false)
+,_scrollbarLocation(NoScrollBar)
+,_wordCharacters(":@-./_~")
+,_bellMode(SystemBeepBell)
+,_blinking(false)
+,_cursorBlinking(false)
+,_hasBlinkingCursor(false)
+,_ctrlDrag(false)
+,_tripleClickMode(SelectWholeLine)
+,_isFixedSize(false)
+,_possibleTripleClick(false)
+,_resizeWidget(0)
+,_resizeTimer(0)
+,_flowControlWarningEnabled(false)
+,_outputSuspendedLabel(0)
+,_lineSpacing(0)
+,_colorsInverted(false)
+,_blendColor(qRgba(0,0,0,0xff))
+,_filterChain(new TerminalImageFilterChain())
+,_cursorShape(BlockCursor)
+{
+  // terminal applications are not designed with Right-To-Left in mind,
+  // so the layout is forced to Left-To-Right
+  setLayoutDirection(Qt::LeftToRight);
+
+  // The offsets are not yet calculated.
+  // Do not calculate these too often to be more smoothly when resizing
+  // konsole in opaque mode.
+  _topMargin = DEFAULT_TOP_MARGIN;
+  _leftMargin = DEFAULT_LEFT_MARGIN;
+
+  // create scroll bar for scrolling output up and down
+  // set the scroll bar's slider to occupy the whole area of the scroll bar initially
+  _scrollBar = new QScrollBar(this);
+  setScroll(0,0); 
+  _scrollBar->setCursor( Qt::ArrowCursor );
+  connect(_scrollBar, SIGNAL(valueChanged(int)), this, 
+  					  SLOT(scrollBarPositionChanged(int)));
+
+  // setup timers for blinking cursor and text
+  _blinkTimer   = new QTimer(this);
+  connect(_blinkTimer, SIGNAL(timeout()), this, SLOT(blinkEvent()));
+  _blinkCursorTimer   = new QTimer(this);
+  connect(_blinkCursorTimer, SIGNAL(timeout()), this, SLOT(blinkCursorEvent()));
+
+//  QCursor::setAutoHideCursor( this, true );
+  
+  setUsesMouse(true);
+  setColorTable(whiteonblack_color_table); 
+//  setColorTable(blackonlightyellow_color_table); 
+  setMouseTracking(true);
+
+  // Enable drag and drop 
+  setAcceptDrops(true); // attempt
+  dragInfo.state = diNone;
+
+  setFocusPolicy( Qt::WheelFocus );
+
+  // enable input method support
+  setAttribute(Qt::WA_InputMethodEnabled, true);
+
+  // this is an important optimization, it tells Qt
+  // that TerminalDisplay will handle repainting its entire area.
+  setAttribute(Qt::WA_OpaquePaintEvent);
+
+  _gridLayout = new QGridLayout(this);
+  _gridLayout->setMargin(0);
+
+  setLayout( _gridLayout ); 
+
+  //set up a warning message when the user presses Ctrl+S to avoid confusion
+  connect( this,SIGNAL(flowControlKeyPressed(bool)),this,SLOT(outputSuspended(bool)) );
+}
+
+TerminalDisplay::~TerminalDisplay()
+{
+  qApp->removeEventFilter( this );
+  
+  delete[] _image;
+
+  delete _gridLayout;
+  delete _outputSuspendedLabel;
+  delete _filterChain;
+}
+
+/* ------------------------------------------------------------------------- */
+/*                                                                           */
+/*                             Display Operations                            */
+/*                                                                           */
+/* ------------------------------------------------------------------------- */
+
+/**
+ A table for emulating the simple (single width) unicode drawing chars.
+ It represents the 250x - 257x glyphs. If it's zero, we can't use it.
+ if it's not, it's encoded as follows: imagine a 5x5 grid where the points are numbered
+ 0 to 24 left to top, top to bottom. Each point is represented by the corresponding bit.
+
+ Then, the pixels basically have the following interpretation:
+ _|||_
+ -...-
+ -...-
+ -...-
+ _|||_
+
+where _ = none
+      | = vertical line.
+      - = horizontal line.
+ */
+
+
+enum LineEncode
+{
+    TopL  = (1<<1),
+    TopC  = (1<<2),
+    TopR  = (1<<3),
+
+    LeftT = (1<<5),
+    Int11 = (1<<6),
+    Int12 = (1<<7),
+    Int13 = (1<<8),
+    RightT = (1<<9),
+
+    LeftC = (1<<10),
+    Int21 = (1<<11),
+    Int22 = (1<<12),
+    Int23 = (1<<13),
+    RightC = (1<<14),
+
+    LeftB = (1<<15),
+    Int31 = (1<<16),
+    Int32 = (1<<17),
+    Int33 = (1<<18),
+    RightB = (1<<19),
+
+    BotL  = (1<<21),
+    BotC  = (1<<22),
+    BotR  = (1<<23)
+};
+
+#include "LineFont.h"
+
+static void drawLineChar(QPainter& paint, int x, int y, int w, int h, uchar code)
+{
+    //Calculate cell midpoints, end points.
+    int cx = x + w/2;
+    int cy = y + h/2;
+    int ex = x + w - 1;
+    int ey = y + h - 1;
+
+    quint32 toDraw = LineChars[code];
+
+    //Top _lines:
+    if (toDraw & TopL)
+        paint.drawLine(cx-1, y, cx-1, cy-2);
+    if (toDraw & TopC)
+        paint.drawLine(cx, y, cx, cy-2);
+    if (toDraw & TopR)
+        paint.drawLine(cx+1, y, cx+1, cy-2);
+
+    //Bot _lines:
+    if (toDraw & BotL)
+        paint.drawLine(cx-1, cy+2, cx-1, ey);
+    if (toDraw & BotC)
+        paint.drawLine(cx, cy+2, cx, ey);
+    if (toDraw & BotR)
+        paint.drawLine(cx+1, cy+2, cx+1, ey);
+
+    //Left _lines:
+    if (toDraw & LeftT)
+        paint.drawLine(x, cy-1, cx-2, cy-1);
+    if (toDraw & LeftC)
+        paint.drawLine(x, cy, cx-2, cy);
+    if (toDraw & LeftB)
+        paint.drawLine(x, cy+1, cx-2, cy+1);
+
+    //Right _lines:
+    if (toDraw & RightT)
+        paint.drawLine(cx+2, cy-1, ex, cy-1);
+    if (toDraw & RightC)
+        paint.drawLine(cx+2, cy, ex, cy);
+    if (toDraw & RightB)
+        paint.drawLine(cx+2, cy+1, ex, cy+1);
+
+    //Intersection points.
+    if (toDraw & Int11)
+        paint.drawPoint(cx-1, cy-1);
+    if (toDraw & Int12)
+        paint.drawPoint(cx, cy-1);
+    if (toDraw & Int13)
+        paint.drawPoint(cx+1, cy-1);
+
+    if (toDraw & Int21)
+        paint.drawPoint(cx-1, cy);
+    if (toDraw & Int22)
+        paint.drawPoint(cx, cy);
+    if (toDraw & Int23)
+        paint.drawPoint(cx+1, cy);
+
+    if (toDraw & Int31)
+        paint.drawPoint(cx-1, cy+1);
+    if (toDraw & Int32)
+        paint.drawPoint(cx, cy+1);
+    if (toDraw & Int33)
+        paint.drawPoint(cx+1, cy+1);
+
+}
+
+void TerminalDisplay::drawLineCharString(	QPainter& painter, int x, int y, const QString& str, 
+									const Character* attributes)
+{
+		const QPen& currentPen = painter.pen();
+		
+		if ( attributes->rendition & RE_BOLD )
+		{
+			QPen boldPen(currentPen);
+			boldPen.setWidth(3);
+			painter.setPen( boldPen );
+		}	
+		
+		for (int i=0 ; i < str.length(); i++)
+		{
+			uchar code = str[i].cell();
+        	if (LineChars[code])
+            	drawLineChar(painter, x + (_fontWidth*i), y, _fontWidth, _fontHeight, code);
+		}
+
+		painter.setPen( currentPen );
+}
+
+void TerminalDisplay::setKeyboardCursorShape(KeyboardCursorShape shape)
+{
+    _cursorShape = shape;
+}
+TerminalDisplay::KeyboardCursorShape TerminalDisplay::keyboardCursorShape() const
+{
+    return _cursorShape;
+}
+void TerminalDisplay::setKeyboardCursorColor(bool useForegroundColor, const QColor& color)
+{
+    if (useForegroundColor)
+        _cursorColor = QColor(); // an invalid color means that
+                                 // the foreground color of the
+                                 // current character should
+                                 // be used
+
+    else
+        _cursorColor = color;
+}
+QColor TerminalDisplay::keyboardCursorColor() const
+{
+    return _cursorColor;
+}
+
+void TerminalDisplay::setOpacity(qreal opacity)
+{
+    QColor color(_blendColor);
+    color.setAlphaF(opacity);
+
+    // enable automatic background filling to prevent the display
+    // flickering if there is no transparency
+    if ( color.alpha() == 255 ) 
+    {
+        setAutoFillBackground(true);
+    }
+    else
+    {
+        setAutoFillBackground(false);
+    }
+
+    _blendColor = color.rgba();
+}
+
+void TerminalDisplay::drawBackground(QPainter& painter, const QRect& rect, const QColor& backgroundColor, bool useOpacitySetting )
+{
+        // the area of the widget showing the contents of the terminal display is drawn
+        // using the background color from the color scheme set with setColorTable()
+        //
+        // the area of the widget behind the scroll-bar is drawn using the background
+        // brush from the scroll-bar's palette, to give the effect of the scroll-bar
+        // being outside of the terminal display and visual consistency with other KDE
+        // applications.  
+        //
+        QRect scrollBarArea = _scrollBar->isVisible() ? 
+                                    rect.intersected(_scrollBar->geometry()) :
+                                    QRect();
+        QRegion contentsRegion = QRegion(rect).subtracted(scrollBarArea);
+        QRect contentsRect = contentsRegion.boundingRect();
+
+        if ( HAVE_TRANSPARENCY && qAlpha(_blendColor) < 0xff && useOpacitySetting ) 
+        {
+            QColor color(backgroundColor);
+            color.setAlpha(qAlpha(_blendColor));
+
+            painter.save();
+            painter.setCompositionMode(QPainter::CompositionMode_Source);
+            painter.fillRect(contentsRect, color);
+            painter.restore();
+        } 
+        else {
+	    painter.fillRect(contentsRect, backgroundColor);
+	}
+
+        painter.fillRect(scrollBarArea,_scrollBar->palette().background());
+}
+
+void TerminalDisplay::drawCursor(QPainter& painter, 
+                                 const QRect& rect,
+                                 const QColor& foregroundColor,
+                                 const QColor& /*backgroundColor*/,
+                                 bool& invertCharacterColor)
+{
+    QRect cursorRect = rect;
+    cursorRect.setHeight(_fontHeight - _lineSpacing - 1);
+    
+    if (!_cursorBlinking)
+    {
+       if ( _cursorColor.isValid() )
+           painter.setPen(_cursorColor);
+       else {
+    	    painter.setPen(foregroundColor);
+	}
+
+       if ( _cursorShape == BlockCursor )
+       {
+            // draw the cursor outline, adjusting the area so that
+            // it is draw entirely inside 'rect'
+            int penWidth = qMax(1,painter.pen().width());
+
+            painter.drawRect(cursorRect.adjusted(penWidth/2,
+                                                 penWidth/2,
+                                                 - penWidth/2 - penWidth%2,
+                                                 - penWidth/2 - penWidth%2));
+            if ( hasFocus() )
+            {
+                painter.fillRect(cursorRect, _cursorColor.isValid() ? _cursorColor : foregroundColor);
+	    
+                if ( !_cursorColor.isValid() )
+                {
+                    // invert the colour used to draw the text to ensure that the character at
+                    // the cursor position is readable
+                    invertCharacterColor = true;
+                }
+            }
+       }
+       else if ( _cursorShape == UnderlineCursor )
+            painter.drawLine(cursorRect.left(),
+                             cursorRect.bottom(),
+                             cursorRect.right(),
+                             cursorRect.bottom());
+       else if ( _cursorShape == IBeamCursor )
+            painter.drawLine(cursorRect.left(),
+                             cursorRect.top(),
+                             cursorRect.left(),
+                             cursorRect.bottom());
+    
+    }
+}
+
+void TerminalDisplay::drawCharacters(QPainter& painter,
+                                     const QRect& rect,
+                                     const QString& text,
+                                     const Character* style,
+                                     bool invertCharacterColor)
+{
+    // don't draw text which is currently blinking
+    if ( _blinking && (style->rendition & RE_BLINK) )
+            return;
+   
+    // setup bold and underline
+    bool useBold = style->rendition & RE_BOLD || style->isBold(_colorTable) || font().bold();
+    bool useUnderline = style->rendition & RE_UNDERLINE || font().underline();
+
+    QFont font = painter.font();
+    if (    font.bold() != useBold 
+         || font.underline() != useUnderline )
+    {
+       font.setBold(useBold);
+       font.setUnderline(useUnderline);
+       painter.setFont(font);
+    }
+
+    const CharacterColor& textColor = ( invertCharacterColor ? style->backgroundColor : style->foregroundColor );
+    const QColor color = textColor.color(_colorTable);
+
+    QPen pen = painter.pen();
+    if ( pen.color() != color )
+    {
+        pen.setColor(color);
+        painter.setPen(color);
+    }
+    // draw text
+    if ( isLineCharString(text) ) {
+	  	drawLineCharString(painter,rect.x(),rect.y(),text,style);
+    }
+    else
+	{
+		// the drawText(rect,flags,string) overload is used here with null flags
+		// instead of drawText(rect,string) because the (rect,string) overload causes 
+		// the application's default layout direction to be used instead of 
+		// the widget-specific layout direction, which should always be
+		// Qt::LeftToRight for this widget
+        painter.drawText(rect,0,text);
+	}
+}
+
+void TerminalDisplay::drawTextFragment(QPainter& painter , 
+                                       const QRect& rect,
+                                       const QString& text, 
+                                       const Character* style)
+{
+    painter.save();
+
+    // setup painter 
+    const QColor foregroundColor = style->foregroundColor.color(_colorTable);
+    const QColor backgroundColor = style->backgroundColor.color(_colorTable);
+    
+    // draw background if different from the display's background color
+    if ( backgroundColor != palette().background().color() )
+        drawBackground(painter,rect,backgroundColor, false /* do not use transparency */);
+
+    // draw cursor shape if the current character is the cursor
+    // this may alter the foreground and background colors
+    bool invertCharacterColor = false;
+
+    if ( style->rendition & RE_CURSOR )
+        drawCursor(painter,rect,foregroundColor,backgroundColor,invertCharacterColor);
+    // draw text
+    drawCharacters(painter,rect,text,style,invertCharacterColor);
+
+    painter.restore();
+}
+
+void TerminalDisplay::setRandomSeed(uint randomSeed) { _randomSeed = randomSeed; }
+uint TerminalDisplay::randomSeed() const { return _randomSeed; }
+
+#if 0
+/*!
+    Set XIM Position
+*/
+void TerminalDisplay::setCursorPos(const int curx, const int cury)
+{
+    QPoint tL  = contentsRect().topLeft();
+    int    tLx = tL.x();
+    int    tLy = tL.y();
+
+    int xpos, ypos;
+    ypos = _topMargin + tLy + _fontHeight*(cury-1) + _fontAscent;
+    xpos = _leftMargin + tLx + _fontWidth*curx;
+    //setMicroFocusHint(xpos, ypos, 0, _fontHeight); //### ???
+    // fprintf(stderr, "x/y = %d/%d\txpos/ypos = %d/%d\n", curx, cury, xpos, ypos);
+    _cursorLine = cury;
+    _cursorCol = curx;
+}
+#endif
+
+// scrolls the image by 'lines', down if lines > 0 or up otherwise.
+//
+// the terminal emulation keeps track of the scrolling of the character 
+// image as it receives input, and when the view is updated, it calls scrollImage() 
+// with the final scroll amount.  this improves performance because scrolling the 
+// display is much cheaper than re-rendering all the text for the 
+// part of the image which has moved up or down.  
+// Instead only new lines have to be drawn
+//
+// note:  it is important that the area of the display which is 
+// scrolled aligns properly with the character grid - 
+// which has a top left point at (_leftMargin,_topMargin) , 
+// a cell width of _fontWidth and a cell height of _fontHeight).    
+void TerminalDisplay::scrollImage(int lines , const QRect& screenWindowRegion)
+{
+	// if the flow control warning is enabled this will interfere with the 
+	// scrolling optimisations and cause artifacts.  the simple solution here
+	// is to just disable the optimisation whilst it is visible
+	if ( _outputSuspendedLabel && _outputSuspendedLabel->isVisible() ) {
+		return;
+	}
+
+    // constrain the region to the display
+    // the bottom of the region is capped to the number of lines in the display's
+    // internal image - 2, so that the height of 'region' is strictly less
+    // than the height of the internal image.
+    QRect region = screenWindowRegion;
+    region.setBottom( qMin(region.bottom(),this->_lines-2) ); 
+
+    if (    lines == 0 
+         || _image == 0
+         || !region.isValid() 
+         || (region.top() + abs(lines)) >= region.bottom() 
+         || this->_lines <= region.height() ) return;
+
+    QRect scrollRect;
+
+    void* firstCharPos = &_image[ region.top() * this->_columns ];
+    void* lastCharPos = &_image[ (region.top() + abs(lines)) * this->_columns ];
+
+    int top = _topMargin + (region.top() * _fontHeight);
+    int linesToMove = region.height() - abs(lines);
+    int bytesToMove = linesToMove * 
+                      this->_columns *
+                      sizeof(Character);
+
+    Q_ASSERT( linesToMove > 0 );
+    Q_ASSERT( bytesToMove > 0 );
+
+    //scroll internal image
+    if ( lines > 0 )
+    {
+        // check that the memory areas that we are going to move are valid
+        Q_ASSERT( (char*)lastCharPos + bytesToMove < 
+                  (char*)(_image + (this->_lines * this->_columns)) );
+        
+        Q_ASSERT( (lines*this->_columns) < _imageSize ); 
+
+        //scroll internal image down
+        memmove( firstCharPos , lastCharPos , bytesToMove ); 
+      
+        //set region of display to scroll, making sure that
+        //the region aligns correctly to the character grid 
+        scrollRect = QRect( _leftMargin , top, 
+                            this->_usedColumns * _fontWidth , 
+                            linesToMove * _fontHeight );
+    }
+    else
+    {
+        // check that the memory areas that we are going to move are valid
+        Q_ASSERT( (char*)firstCharPos + bytesToMove < 
+                  (char*)(_image + (this->_lines * this->_columns)) );
+
+        //scroll internal image up
+        memmove( lastCharPos , firstCharPos , bytesToMove ); 
+     
+        //set region of the display to scroll, making sure that
+        //the region aligns correctly to the character grid
+        QPoint topPoint( _leftMargin , top + abs(lines)*_fontHeight );
+
+        scrollRect = QRect( topPoint ,
+                     QSize( this->_usedColumns*_fontWidth , 
+                            linesToMove * _fontHeight ));
+    }
+
+    //scroll the display vertically to match internal _image
+    scroll( 0 , _fontHeight * (-lines) , scrollRect );
+}
+
+QRegion TerminalDisplay::hotSpotRegion() const 
+{
+	QRegion region;
+	foreach( Filter::HotSpot* hotSpot , _filterChain->hotSpots() )
+	{
+		QRect rect;
+		rect.setLeft(hotSpot->startColumn());
+		rect.setTop(hotSpot->startLine());
+		rect.setRight(hotSpot->endColumn());
+		rect.setBottom(hotSpot->endLine());
+
+		region |= imageToWidget(rect); 
+	}
+	return region;
+}
+
+void TerminalDisplay::processFilters() 
+{
+	if (!_screenWindow)
+		return;
+
+	QRegion preUpdateHotSpots = hotSpotRegion();
+
+	// use _screenWindow->getImage() here rather than _image because
+	// other classes may call processFilters() when this display's
+	// ScreenWindow emits a scrolled() signal - which will happen before
+	// updateImage() is called on the display and therefore _image is 
+	// out of date at this point
+	_filterChain->setImage( _screenWindow->getImage(),
+							_screenWindow->windowLines(),
+							_screenWindow->windowColumns(),
+							_screenWindow->getLineProperties() );
+    _filterChain->process();
+
+	QRegion postUpdateHotSpots = hotSpotRegion();
+
+	update( preUpdateHotSpots | postUpdateHotSpots );
+}
+
+void TerminalDisplay::updateImage() 
+{
+  if ( !_screenWindow )
+      return;
+
+  // optimization - scroll the existing image where possible and 
+  // avoid expensive text drawing for parts of the image that 
+  // can simply be moved up or down
+  scrollImage( _screenWindow->scrollCount() ,
+               _screenWindow->scrollRegion() );
+  _screenWindow->resetScrollCount();
+
+  Character* const newimg = _screenWindow->getImage();
+  int lines = _screenWindow->windowLines();
+  int columns = _screenWindow->windowColumns();
+
+  setScroll( _screenWindow->currentLine() , _screenWindow->lineCount() );
+
+  if (!_image)
+     updateImageSize(); // Create _image
+
+  Q_ASSERT( this->_usedLines <= this->_lines );
+  Q_ASSERT( this->_usedColumns <= this->_columns );
+
+  int y,x,len;
+
+  QPoint tL  = contentsRect().topLeft();
+
+  int    tLx = tL.x();
+  int    tLy = tL.y();
+  _hasBlinker = false;
+
+  CharacterColor cf;       // undefined
+  CharacterColor _clipboard;       // undefined
+  int cr  = -1;   // undefined
+
+  const int linesToUpdate = qMin(this->_lines, qMax(0,lines  ));
+  const int columnsToUpdate = qMin(this->_columns,qMax(0,columns));
+
+  QChar *disstrU = new QChar[columnsToUpdate];
+  char *dirtyMask = new char[columnsToUpdate+2]; 
+  QRegion dirtyRegion;
+
+  // debugging variable, this records the number of lines that are found to
+  // be 'dirty' ( ie. have changed from the old _image to the new _image ) and
+  // which therefore need to be repainted
+  int dirtyLineCount = 0;
+
+  for (y = 0; y < linesToUpdate; y++)
+  {
+    const Character*       currentLine = &_image[y*this->_columns];
+    const Character* const newLine = &newimg[y*columns];
+
+    bool updateLine = false;
+    
+    // The dirty mask indicates which characters need repainting. We also
+    // mark surrounding neighbours dirty, in case the character exceeds
+    // its cell boundaries
+    memset(dirtyMask, 0, columnsToUpdate+2);
+   
+    for( x = 0 ; x < columnsToUpdate ; x++)
+    {
+        if ( newLine[x] != currentLine[x] ) 
+        {
+            dirtyMask[x] = true;
+        }
+    }
+
+    if (!_resizing) // not while _resizing, we're expecting a paintEvent
+    for (x = 0; x < columnsToUpdate; x++)
+    {
+      _hasBlinker |= (newLine[x].rendition & RE_BLINK);
+    
+      // Start drawing if this character or the next one differs.
+      // We also take the next one into account to handle the situation
+      // where characters exceed their cell width.
+      if (dirtyMask[x])
+      {
+        quint16 c = newLine[x+0].character;
+        if ( !c )
+            continue;
+        int p = 0;
+        disstrU[p++] = c; //fontMap(c);
+        bool lineDraw = isLineChar(c);
+        bool doubleWidth = (x+1 == columnsToUpdate) ? false : (newLine[x+1].character == 0);
+        cr = newLine[x].rendition;
+        _clipboard = newLine[x].backgroundColor;
+        if (newLine[x].foregroundColor != cf) cf = newLine[x].foregroundColor;
+        int lln = columnsToUpdate - x;
+        for (len = 1; len < lln; len++)
+        {
+            const Character& ch = newLine[x+len];
+
+            if (!ch.character)
+                continue; // Skip trailing part of multi-col chars.
+
+			bool nextIsDoubleWidth = (x+len+1 == columnsToUpdate) ? false : (newLine[x+len+1].character == 0);
+
+            if (  ch.foregroundColor != cf || 
+                  ch.backgroundColor != _clipboard || 
+                  ch.rendition != cr ||
+                  !dirtyMask[x+len] || 
+                  isLineChar(c) != lineDraw || 
+                  nextIsDoubleWidth != doubleWidth )
+            break;
+
+          disstrU[p++] = c; //fontMap(c);
+        }
+
+        QString unistr(disstrU, p);
+
+        bool saveFixedFont = _fixedFont;
+        if (lineDraw)
+           _fixedFont = false;
+        if (doubleWidth)
+           _fixedFont = false;
+
+		updateLine = true;
+
+		_fixedFont = saveFixedFont;
+        x += len - 1;
+      }
+      
+    }
+
+	//both the top and bottom halves of double height _lines must always be redrawn
+	//although both top and bottom halves contain the same characters, only 
+    //the top one is actually 
+	//drawn.
+    if (_lineProperties.count() > y)
+        updateLine |= (_lineProperties[y] & LINE_DOUBLEHEIGHT);
+
+    // if the characters on the line are different in the old and the new _image
+    // then this line must be repainted.    
+    if (updateLine)
+    {
+        dirtyLineCount++;
+
+        // add the area occupied by this line to the region which needs to be
+        // repainted
+        QRect dirtyRect = QRect( _leftMargin+tLx , 
+                                 _topMargin+tLy+_fontHeight*y , 
+                                 _fontWidth * columnsToUpdate , 
+                                 _fontHeight ); 	
+
+        dirtyRegion |= dirtyRect;
+    }
+
+    // replace the line of characters in the old _image with the 
+    // current line of the new _image 
+    memcpy((void*)currentLine,(const void*)newLine,columnsToUpdate*sizeof(Character));
+  }
+
+  // if the new _image is smaller than the previous _image, then ensure that the area
+  // outside the new _image is cleared 
+  if ( linesToUpdate < _usedLines )
+  {
+    dirtyRegion |= QRect(   _leftMargin+tLx , 
+                            _topMargin+tLy+_fontHeight*linesToUpdate , 
+                            _fontWidth * this->_columns , 
+                            _fontHeight * (_usedLines-linesToUpdate) );
+  }
+  _usedLines = linesToUpdate;
+  
+  if ( columnsToUpdate < _usedColumns )
+  {
+    dirtyRegion |= QRect(   _leftMargin+tLx+columnsToUpdate*_fontWidth , 
+                            _topMargin+tLy , 
+                            _fontWidth * (_usedColumns-columnsToUpdate) , 
+                            _fontHeight * this->_lines );
+  }
+  _usedColumns = columnsToUpdate;
+
+  dirtyRegion |= _inputMethodData.previousPreeditRect;
+
+  // update the parts of the display which have changed
+  update(dirtyRegion);
+
+  if ( _hasBlinker && !_blinkTimer->isActive()) _blinkTimer->start( BLINK_DELAY ); 
+  if (!_hasBlinker && _blinkTimer->isActive()) { _blinkTimer->stop(); _blinking = false; }
+  delete[] dirtyMask;
+  delete[] disstrU;
+
+}
+
+void TerminalDisplay::showResizeNotification()
+{
+  if (_terminalSizeHint && isVisible())
+  {
+     if (_terminalSizeStartup) {
+       		_terminalSizeStartup=false;
+       return;
+     }
+     if (!_resizeWidget)
+     {
+        _resizeWidget = new QLabel(("Size: XXX x XXX"), this);
+        _resizeWidget->setMinimumWidth(_resizeWidget->fontMetrics().width(("Size: XXX x XXX")));
+        _resizeWidget->setMinimumHeight(_resizeWidget->sizeHint().height());
+		_resizeWidget->setAlignment(Qt::AlignCenter);
+
+        _resizeWidget->setStyleSheet("background-color:palette(window);border-style:solid;border-width:1px;border-color:palette(dark)");
+
+		_resizeTimer = new QTimer(this);
+		_resizeTimer->setSingleShot(true);
+        connect(_resizeTimer, SIGNAL(timeout()), _resizeWidget, SLOT(hide()));
+
+     }
+     QString sizeStr;
+     sizeStr.sprintf("Size: %d x %d", _columns, _lines);
+     _resizeWidget->setText(sizeStr);
+     _resizeWidget->move((width()-_resizeWidget->width())/2,
+                         (height()-_resizeWidget->height())/2+20);
+     _resizeWidget->show();
+     _resizeTimer->start(1000);
+  }
+}
+
+void TerminalDisplay::setBlinkingCursor(bool blink)
+{
+  _hasBlinkingCursor=blink;
+  
+  if (blink && !_blinkCursorTimer->isActive()) 
+      _blinkCursorTimer->start(BLINK_DELAY);
+  
+  if (!blink && _blinkCursorTimer->isActive()) 
+  {
+    _blinkCursorTimer->stop();
+    if (_cursorBlinking)
+      blinkCursorEvent();
+    else
+      _cursorBlinking = false;
+  }
+}
+
+void TerminalDisplay::paintEvent( QPaintEvent* pe )
+{
+//qDebug("%s %d paintEvent", __FILE__, __LINE__);
+  QPainter paint(this);
+
+  foreach (QRect rect, (pe->region() & contentsRect()).rects())
+  {
+    drawBackground(paint,rect,palette().background().color(),	true /* use opacity setting */);
+    drawContents(paint, rect);    
+  }
+//    drawBackground(paint,contentsRect(),palette().background().color(),	true /* use opacity setting */);
+//    drawContents(paint, contentsRect());    
+  drawInputMethodPreeditString(paint,preeditRect());
+  paintFilters(paint);
+
+  paint.end();
+}
+
+QPoint TerminalDisplay::cursorPosition() const
+{
+	if (_screenWindow)
+		return _screenWindow->cursorPosition();
+	else
+		return QPoint(0,0);
+}
+
+QRect TerminalDisplay::preeditRect() const
+{
+    const int preeditLength = string_width(_inputMethodData.preeditString);
+
+    if ( preeditLength == 0 )
+        return QRect();
+
+    return QRect(_leftMargin + _fontWidth*cursorPosition().x(),
+                 _topMargin + _fontHeight*cursorPosition().y(),
+                 _fontWidth*preeditLength,
+                 _fontHeight);
+}   
+
+void TerminalDisplay::drawInputMethodPreeditString(QPainter& painter , const QRect& rect)
+{
+    if ( _inputMethodData.preeditString.isEmpty() ) {
+        return;
+    }
+    const QPoint cursorPos = cursorPosition(); 
+
+    bool invertColors = false;
+    const QColor background = _colorTable[DEFAULT_BACK_COLOR].color;
+    const QColor foreground = _colorTable[DEFAULT_FORE_COLOR].color;
+    const Character* style = &_image[loc(cursorPos.x(),cursorPos.y())];
+
+    drawBackground(painter,rect,background,true);
+    drawCursor(painter,rect,foreground,background,invertColors);
+    drawCharacters(painter,rect,_inputMethodData.preeditString,style,invertColors);
+
+    _inputMethodData.previousPreeditRect = rect; 
+}
+
+FilterChain* TerminalDisplay::filterChain() const
+{
+    return _filterChain;
+}
+
+void TerminalDisplay::paintFilters(QPainter& painter)
+{
+//qDebug("%s %d paintFilters", __FILE__, __LINE__);
+
+    // get color of character under mouse and use it to draw
+    // lines for filters
+    QPoint cursorPos = mapFromGlobal(QCursor::pos());
+    int cursorLine;
+    int cursorColumn;
+    getCharacterPosition( cursorPos , cursorLine , cursorColumn );
+    Character cursorCharacter = _image[loc(cursorColumn,cursorLine)];
+
+    painter.setPen( QPen(cursorCharacter.foregroundColor.color(colorTable())) );
+
+    // iterate over hotspots identified by the display's currently active filters 
+    // and draw appropriate visuals to indicate the presence of the hotspot
+
+    QList<Filter::HotSpot*> spots = _filterChain->hotSpots();
+    QListIterator<Filter::HotSpot*> iter(spots);
+    while (iter.hasNext())
+    {
+        Filter::HotSpot* spot = iter.next();
+
+        for ( int line = spot->startLine() ; line <= spot->endLine() ; line++ )
+        {
+            int startColumn = 0;
+            int endColumn = _columns-1; // TODO use number of _columns which are actually 
+                                        // occupied on this line rather than the width of the 
+                                        // display in _columns
+
+            // ignore whitespace at the end of the lines
+            while ( QChar(_image[loc(endColumn,line)].character).isSpace() && endColumn > 0 )
+                endColumn--;
+              
+            // increment here because the column which we want to set 'endColumn' to
+            // is the first whitespace character at the end of the line
+            endColumn++;
+
+            if ( line == spot->startLine() )
+                startColumn = spot->startColumn();
+            if ( line == spot->endLine() )
+                endColumn = spot->endColumn();
+
+            // subtract one pixel from
+            // the right and bottom so that
+            // we do not overdraw adjacent
+            // hotspots
+            //
+            // subtracting one pixel from all sides also prevents an edge case where
+            // moving the mouse outside a link could still leave it underlined 
+            // because the check below for the position of the cursor
+            // finds it on the border of the target area
+            QRect r;
+            r.setCoords( startColumn*_fontWidth + 1, line*_fontHeight + 1,
+                             endColumn*_fontWidth - 1, (line+1)*_fontHeight - 1 ); 
+                                                                           
+            // Underline link hotspots 
+            if ( spot->type() == Filter::HotSpot::Link )
+            {
+                QFontMetrics metrics(font());
+        
+                // find the baseline (which is the invisible line that the characters in the font sit on,
+                // with some having tails dangling below)
+                int baseline = r.bottom() - metrics.descent();
+                // find the position of the underline below that
+                int underlinePos = baseline + metrics.underlinePos();
+
+                if ( r.contains( mapFromGlobal(QCursor::pos()) ) )
+                    painter.drawLine( r.left() , underlinePos , 
+                                      r.right() , underlinePos );
+            }
+            // Marker hotspots simply have a transparent rectanglular shape
+            // drawn on top of them
+            else if ( spot->type() == Filter::HotSpot::Marker )
+            {
+            //TODO - Do not use a hardcoded colour for this
+                painter.fillRect(r,QBrush(QColor(255,0,0,120)));
+            }
+        }
+    }
+}
+void TerminalDisplay::drawContents(QPainter &paint, const QRect &rect)
+{
+//qDebug("%s %d drawContents and rect x=%d y=%d w=%d h=%d", __FILE__, __LINE__, rect.x(), rect.y(),rect.width(),rect.height());
+
+  QPoint tL  = contentsRect().topLeft();
+//  int    tLx = tL.x();
+  int    tLy = tL.y();
+
+  int tLx = (_contentWidth - _usedColumns * _fontWidth)/2;
+//  int tLy = (_contentHeight - _usedLines * _fontHeight)/2; 
+//qDebug("%d %d %d %d", tLx, tLy, _contentWidth, _usedColumns * _fontWidth);  
+
+  int lux = qMin(_usedColumns-1, qMax(0,(rect.left()   - tLx - _leftMargin ) / _fontWidth));
+  int luy = qMin(_usedLines-1,  qMax(0, (rect.top()    - tLy - _topMargin  ) / _fontHeight));
+  int rlx = qMin(_usedColumns-1, qMax(0, (rect.right()  - tLx - _leftMargin ) / _fontWidth));
+  int rly = qMin(_usedLines-1,  qMax(0, (rect.bottom() - tLy - _topMargin  ) / _fontHeight));
+
+  const int bufferSize = _usedColumns;
+  QChar *disstrU = new QChar[bufferSize];
+  for (int y = luy; y <= rly; y++)
+  {
+    quint16 c = _image[loc(lux,y)].character;
+    int x = lux;
+    if(!c && x)
+      x--; // Search for start of multi-column character
+    for (; x <= rlx; x++)
+    {
+      int len = 1;
+      int p = 0;
+
+      // is this a single character or a sequence of characters ?
+      if ( _image[loc(x,y)].rendition & RE_EXTENDED_CHAR )
+      {
+        // sequence of characters
+        ushort extendedCharLength = 0;
+        ushort* chars = ExtendedCharTable::instance
+                            .lookupExtendedChar(_image[loc(x,y)].charSequence,extendedCharLength);
+        for ( int index = 0 ; index < extendedCharLength ; index++ ) 
+        {
+            Q_ASSERT( p < bufferSize );
+            disstrU[p++] = chars[index];
+        }
+      }
+      else
+      {
+        // single character
+        c = _image[loc(x,y)].character;
+        if (c)
+        {
+             Q_ASSERT( p < bufferSize );
+             disstrU[p++] = c; //fontMap(c);
+        }
+      }
+
+      bool lineDraw = isLineChar(c);
+      bool doubleWidth = (_image[ qMin(loc(x,y)+1,_imageSize) ].character == 0);
+      CharacterColor currentForeground = _image[loc(x,y)].foregroundColor;
+      CharacterColor currentBackground = _image[loc(x,y)].backgroundColor;
+      quint8 currentRendition = _image[loc(x,y)].rendition;
+	  
+      while (x+len <= rlx &&
+             _image[loc(x+len,y)].foregroundColor == currentForeground &&
+             _image[loc(x+len,y)].backgroundColor == currentBackground &&
+             _image[loc(x+len,y)].rendition == currentRendition &&
+             (_image[ qMin(loc(x+len,y)+1,_imageSize) ].character == 0) == doubleWidth &&
+             isLineChar( c = _image[loc(x+len,y)].character) == lineDraw) // Assignment!
+      {
+        if (c)
+          disstrU[p++] = c; //fontMap(c);
+        if (doubleWidth) // assert((_image[loc(x+len,y)+1].character == 0)), see above if condition
+          len++; // Skip trailing part of multi-column character
+        len++;
+      }
+      if ((x+len < _usedColumns) && (!_image[loc(x+len,y)].character))
+        len++; // Adjust for trailing part of multi-column character
+
+   	     bool save__fixedFont = _fixedFont;
+         if (lineDraw)
+            _fixedFont = false;
+         if (doubleWidth)
+            _fixedFont = false;
+         QString unistr(disstrU,p);
+		 
+		 if (y < _lineProperties.size())
+		 {
+			if (_lineProperties[y] & LINE_DOUBLEWIDTH) {
+				paint.scale(2,1);
+			}
+			
+			if (_lineProperties[y] & LINE_DOUBLEHEIGHT) {
+  		 		paint.scale(1,2);
+			}
+		 }
+
+		 //calculate the area in which the text will be drawn
+		 QRect textArea = QRect( _leftMargin+tLx+_fontWidth*x , 
+					_topMargin+tLy+_fontHeight*y , 
+					_fontWidth*len, 
+					_fontHeight);
+		
+		 //move the calculated area to take account of scaling applied to the painter.
+		 //the position of the area from the origin (0,0) is scaled 
+         //by the opposite of whatever
+		 //transformation has been applied to the painter.  this ensures that 
+		 //painting does actually start from textArea.topLeft() 
+         //(instead of textArea.topLeft() * painter-scale)	
+		 QMatrix inverted = paint.matrix().inverted();
+//		 textArea.moveTopLeft( inverted.map(textArea.topLeft()) );
+		 textArea.moveCenter( inverted.map(textArea.center()) );
+
+		 
+		 //paint text fragment
+         drawTextFragment(	paint,
+                		    textArea,
+                		    unistr, 
+					    	&_image[loc(x,y)] ); //, 
+						    //0, 
+						    //!_isPrinting );
+         
+		 _fixedFont = save__fixedFont;
+     
+		 //reset back to single-width, single-height _lines 
+		 paint.resetMatrix();
+
+		 if (y < _lineProperties.size()-1)
+		 {
+			//double-height _lines are represented by two adjacent _lines 
+            //containing the same characters
+			//both _lines will have the LINE_DOUBLEHEIGHT attribute.  
+            //If the current line has the LINE_DOUBLEHEIGHT attribute, 
+            //we can therefore skip the next line
+			if (_lineProperties[y] & LINE_DOUBLEHEIGHT)
+				y++;
+		 }
+		 
+	    x += len - 1;
+    }
+  }
+  delete [] disstrU;
+}
+
+void TerminalDisplay::blinkEvent()
+{
+  _blinking = !_blinking;
+
+  //TODO:  Optimise to only repaint the areas of the widget 
+  // where there is blinking text
+  // rather than repainting the whole widget.
+  update();
+}
+
+QRect TerminalDisplay::imageToWidget(const QRect& imageArea) const
+{
+//qDebug("%s %d imageToWidget", __FILE__, __LINE__);
+    QRect result;
+    result.setLeft( _leftMargin + _fontWidth * imageArea.left() );
+    result.setTop( _topMargin + _fontHeight * imageArea.top() );
+    result.setWidth( _fontWidth * imageArea.width() );
+    result.setHeight( _fontHeight * imageArea.height() );
+
+    return result;
+}
+
+void TerminalDisplay::blinkCursorEvent()
+{
+  _cursorBlinking = !_cursorBlinking;
+
+  QRect cursorRect = imageToWidget( QRect(cursorPosition(),QSize(1,1)) ); 
+
+  update(cursorRect);
+}
+
+/* ------------------------------------------------------------------------- */
+/*                                                                           */
+/*                                  Resizing                                 */
+/*                                                                           */
+/* ------------------------------------------------------------------------- */
+
+void TerminalDisplay::resizeEvent(QResizeEvent*)
+{
+  updateImageSize();
+}
+
+void TerminalDisplay::propagateSize()
+{
+  if (_isFixedSize)
+  {
+     setSize(_columns, _lines);
+     QWidget::setFixedSize(sizeHint());
+     parentWidget()->adjustSize();
+     parentWidget()->setFixedSize(parentWidget()->sizeHint());
+     return;
+  }
+  if (_image)
+     updateImageSize();
+}
+
+void TerminalDisplay::updateImageSize()
+{
+//qDebug("%s %d updateImageSize", __FILE__, __LINE__);
+  Character* oldimg = _image;
+  int oldlin = _lines;
+  int oldcol = _columns;
+
+  makeImage();
+
+  
+  // copy the old image to reduce flicker
+  int lines = qMin(oldlin,_lines);
+  int columns = qMin(oldcol,_columns);
+
+  if (oldimg)
+  {
+    for (int line = 0; line < lines; line++) 
+    {
+      memcpy((void*)&_image[_columns*line],
+             (void*)&oldimg[oldcol*line],columns*sizeof(Character));
+    }
+    delete[] oldimg;
+  }
+
+  if (_screenWindow)
+  	_screenWindow->setWindowLines(_lines);
+
+  _resizing = (oldlin!=_lines) || (oldcol!=_columns);
+
+  if ( _resizing )
+  {
+  	showResizeNotification();
+    emit changedContentSizeSignal(_contentHeight, _contentWidth); // expose resizeEvent
+  }
+  
+  _resizing = false;
+}
+
+//showEvent and hideEvent are reimplemented here so that it appears to other classes that the 
+//display has been resized when the display is hidden or shown.
+//
+//this allows  
+//TODO: Perhaps it would be better to have separate signals for show and hide instead of using
+//the same signal as the one for a content size change 
+void TerminalDisplay::showEvent(QShowEvent*)
+{
+    emit changedContentSizeSignal(_contentHeight,_contentWidth);
+}
+void TerminalDisplay::hideEvent(QHideEvent*)
+{
+    emit changedContentSizeSignal(_contentHeight,_contentWidth);
+}
+
+/* ------------------------------------------------------------------------- */
+/*                                                                           */
+/*                                Scrollbar                                  */
+/*                                                                           */
+/* ------------------------------------------------------------------------- */
+
+void TerminalDisplay::scrollBarPositionChanged(int)
+{
+  if ( !_screenWindow ) 
+      return;
+
+  _screenWindow->scrollTo( _scrollBar->value() );
+
+  // if the thumb has been moved to the bottom of the _scrollBar then set
+  // the display to automatically track new output, 
+  // that is, scroll down automatically
+  // to how new _lines as they are added
+  const bool atEndOfOutput = (_scrollBar->value() == _scrollBar->maximum());
+  _screenWindow->setTrackOutput( atEndOfOutput );
+
+  updateImage();
+}
+
+void TerminalDisplay::setScroll(int cursor, int slines)
+{
+//qDebug("%s %d setScroll", __FILE__, __LINE__);
+  // update _scrollBar if the range or value has changed,
+  // otherwise return
+  //
+  // setting the range or value of a _scrollBar will always trigger
+  // a repaint, so it should be avoided if it is not necessary
+  if ( _scrollBar->minimum() == 0                 &&
+       _scrollBar->maximum() == (slines - _lines) &&
+       _scrollBar->value()   == cursor )
+  {
+        return;
+  }
+
+  disconnect(_scrollBar, SIGNAL(valueChanged(int)), this, SLOT(scrollBarPositionChanged(int)));
+  _scrollBar->setRange(0,slines - _lines);
+  _scrollBar->setSingleStep(1);
+  _scrollBar->setPageStep(_lines);
+  _scrollBar->setValue(cursor);
+  connect(_scrollBar, SIGNAL(valueChanged(int)), this, SLOT(scrollBarPositionChanged(int)));
+}
+
+void TerminalDisplay::setScrollBarPosition(ScrollBarPosition position)
+{
+  if (_scrollbarLocation == position) {
+//      return; 
+  }
+ 
+  if ( position == NoScrollBar )
+     _scrollBar->hide();
+  else 
+     _scrollBar->show(); 
+
+  _topMargin = _leftMargin = 1;
+  _scrollbarLocation = position;
+  
+  propagateSize();
+  update();
+}
+
+void TerminalDisplay::mousePressEvent(QMouseEvent* ev)
+{
+  if ( _possibleTripleClick && (ev->button()==Qt::LeftButton) ) {
+    mouseTripleClickEvent(ev);
+    return;
+  }
+
+  if ( !contentsRect().contains(ev->pos()) ) return;
+  
+  if ( !_screenWindow ) return;
+
+  int charLine;
+  int charColumn;
+  getCharacterPosition(ev->pos(),charLine,charColumn);
+  QPoint pos = QPoint(charColumn,charLine);
+
+  if ( ev->button() == Qt::LeftButton)
+  {
+    _lineSelectionMode = false;
+    _wordSelectionMode = false;
+
+    emit isBusySelecting(true); // Keep it steady...
+    // Drag only when the Control key is hold
+    bool selected = false;
+    
+    // The receiver of the testIsSelected() signal will adjust
+    // 'selected' accordingly.
+    //emit testIsSelected(pos.x(), pos.y(), selected);
+    
+    selected =  _screenWindow->isSelected(pos.x(),pos.y());
+
+    if ((!_ctrlDrag || ev->modifiers() & Qt::ControlModifier) && selected ) {
+      // The user clicked inside selected text
+      dragInfo.state = diPending;
+      dragInfo.start = ev->pos();
+    }
+    else {
+      // No reason to ever start a drag event
+      dragInfo.state = diNone;
+
+      _preserveLineBreaks = !( ( ev->modifiers() & Qt::ControlModifier ) && !(ev->modifiers() & Qt::AltModifier) );
+      _columnSelectionMode = (ev->modifiers() & Qt::AltModifier) && (ev->modifiers() & Qt::ControlModifier);
+
+      if (_mouseMarks || (ev->modifiers() & Qt::ShiftModifier))
+      {
+         _screenWindow->clearSelection();
+
+        //emit clearSelectionSignal();
+        pos.ry() += _scrollBar->value();
+        _iPntSel = _pntSel = pos;
+        _actSel = 1; // left mouse button pressed but nothing selected yet.
+        
+      }
+      else
+      {
+        emit mouseSignal( 0, charColumn + 1, charLine + 1 +_scrollBar->value() -_scrollBar->maximum() , 0);
+      }
+    }
+  }
+  else if ( ev->button() == Qt::MidButton )
+  {
+    if ( _mouseMarks || (!_mouseMarks && (ev->modifiers() & Qt::ShiftModifier)) )
+      emitSelection(true,ev->modifiers() & Qt::ControlModifier);
+    else
+      emit mouseSignal( 1, charColumn +1, charLine +1 +_scrollBar->value() -_scrollBar->maximum() , 0);
+  }
+  else if ( ev->button() == Qt::RightButton )
+  {
+    if (_mouseMarks || (ev->modifiers() & Qt::ShiftModifier)) 
+    {
+        emit configureRequest( this, 
+                               ev->modifiers() & (Qt::ShiftModifier|Qt::ControlModifier), 
+                               ev->pos()
+                             );
+    }
+    else
+      emit mouseSignal( 2, charColumn +1, charLine +1 +_scrollBar->value() -_scrollBar->maximum() , 0);
+  }
+}
+
+QList<QAction*> TerminalDisplay::filterActions(const QPoint& position)
+{
+  int charLine, charColumn;
+  getCharacterPosition(position,charLine,charColumn);
+
+  Filter::HotSpot* spot = _filterChain->hotSpotAt(charLine,charColumn);
+
+  return spot ? spot->actions() : QList<QAction*>();
+}
+
+void TerminalDisplay::mouseMoveEvent(QMouseEvent* ev)
+{
+  int charLine = 0;
+  int charColumn = 0;
+
+  getCharacterPosition(ev->pos(),charLine,charColumn); 
+
+  // handle filters
+  // change link hot-spot appearance on mouse-over
+  Filter::HotSpot* spot = _filterChain->hotSpotAt(charLine,charColumn);
+  if ( spot && spot->type() == Filter::HotSpot::Link)
+  {
+    QRect previousHotspotArea = _mouseOverHotspotArea;
+    _mouseOverHotspotArea.setCoords( qMin(spot->startColumn() , spot->endColumn()) * _fontWidth,
+                                     spot->startLine() * _fontHeight,
+                                     qMax(spot->startColumn() , spot->endColumn()) * _fontHeight,
+                                     (spot->endLine()+1) * _fontHeight );
+
+    // display tooltips when mousing over links
+    // TODO: Extend this to work with filter types other than links
+    const QString& tooltip = spot->tooltip();
+    if ( !tooltip.isEmpty() )
+    {
+        QToolTip::showText( mapToGlobal(ev->pos()) , tooltip , this , _mouseOverHotspotArea );
+    }
+
+    update( _mouseOverHotspotArea | previousHotspotArea );
+  }
+  else if ( _mouseOverHotspotArea.isValid() )
+  {
+        update( _mouseOverHotspotArea );
+        // set hotspot area to an invalid rectangle
+        _mouseOverHotspotArea = QRect();
+  }
+  
+  // for auto-hiding the cursor, we need mouseTracking
+  if (ev->buttons() == Qt::NoButton ) return;
+
+  // if the terminal is interested in mouse movements 
+  // then emit a mouse movement signal, unless the shift
+  // key is being held down, which overrides this.
+  if (!_mouseMarks && !(ev->modifiers() & Qt::ShiftModifier))
+  {
+	int button = 3;
+	if (ev->buttons() & Qt::LeftButton)
+		button = 0;
+	if (ev->buttons() & Qt::MidButton)
+		button = 1;
+	if (ev->buttons() & Qt::RightButton)
+		button = 2;
+
+        
+        emit mouseSignal( button, 
+                        charColumn + 1,
+                        charLine + 1 +_scrollBar->value() -_scrollBar->maximum(),
+			 1 );
+      
+	return;
+  }
+      
+  if (dragInfo.state == diPending) 
+  {
+    // we had a mouse down, but haven't confirmed a drag yet
+    // if the mouse has moved sufficiently, we will confirm
+
+   int distance = 10; //KGlobalSettings::dndEventDelay();
+   if ( ev->x() > dragInfo.start.x() + distance || ev->x() < dragInfo.start.x() - distance ||
+        ev->y() > dragInfo.start.y() + distance || ev->y() < dragInfo.start.y() - distance) 
+   {
+      // we've left the drag square, we can start a real drag operation now
+      emit isBusySelecting(false); // Ok.. we can breath again.
+      
+       _screenWindow->clearSelection();
+      doDrag();
+    }
+    return;
+  } 
+  else if (dragInfo.state == diDragging) 
+  {
+    // this isn't technically needed because mouseMoveEvent is suppressed during
+    // Qt drag operations, replaced by dragMoveEvent
+    return;
+  }
+
+  if (_actSel == 0) return;
+
+ // don't extend selection while pasting
+  if (ev->buttons() & Qt::MidButton) return;
+
+  extendSelection( ev->pos() );
+}
+
+#if 0
+void TerminalDisplay::setSelectionEnd()
+{
+  extendSelection( _configureRequestPoint );
+}
+#endif
+
+void TerminalDisplay::extendSelection( const QPoint& position )
+{
+  QPoint pos = position;
+
+  if ( !_screenWindow )
+      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 caught within the bounds of the text in
+  // this widget.
+
+  // Adjust position within text area bounds. See FIXME above.
+  QPoint oldpos = pos;
+  if ( pos.x() < tLx+_leftMargin )                  
+      pos.setX( tLx+_leftMargin );
+  if ( pos.x() > tLx+_leftMargin+_usedColumns*_fontWidth-1 ) 
+      pos.setX( tLx+_leftMargin+_usedColumns*_fontWidth );
+  if ( pos.y() < tLy+_topMargin )                   
+      pos.setY( tLy+_topMargin );
+  if ( pos.y() > tLy+_topMargin+_usedLines*_fontHeight-1 )    
+      pos.setY( tLy+_topMargin+_usedLines*_fontHeight-1 );
+
+  if ( pos.y() == tLy+_topMargin+_usedLines*_fontHeight-1 )
+  {
+    _scrollBar->setValue(_scrollBar->value()+yMouseScroll); // scrollforward
+  }
+  if ( pos.y() == tLy+_topMargin )
+  {
+    _scrollBar->setValue(_scrollBar->value()-yMouseScroll); // scrollback
+  }
+
+  int charColumn = 0;
+  int charLine = 0;
+  getCharacterPosition(pos,charLine,charColumn);
+
+  QPoint here = QPoint(charColumn,charLine); //QPoint((pos.x()-tLx-_leftMargin+(_fontWidth/2))/_fontWidth,(pos.y()-tLy-_topMargin)/_fontHeight);
+  QPoint ohere;
+  QPoint _iPntSelCorr = _iPntSel;
+  _iPntSelCorr.ry() -= _scrollBar->value();
+  QPoint _pntSelCorr = _pntSel;
+  _pntSelCorr.ry() -= _scrollBar->value();
+  bool swapping = false;
+
+  if ( _wordSelectionMode )
+  {
+    // Extend to word boundaries
+    int i;
+    int selClass;
+
+    bool left_not_right = ( here.y() < _iPntSelCorr.y() ||
+	   here.y() == _iPntSelCorr.y() && here.x() < _iPntSelCorr.x() );
+    bool old_left_not_right = ( _pntSelCorr.y() < _iPntSelCorr.y() ||
+	   _pntSelCorr.y() == _iPntSelCorr.y() && _pntSelCorr.x() < _iPntSelCorr.x() );
+    swapping = left_not_right != old_left_not_right;
+
+    // Find left (left_not_right ? from here : from start)
+    QPoint left = left_not_right ? here : _iPntSelCorr;
+    i = loc(left.x(),left.y());
+    if (i>=0 && i<=_imageSize) {
+      selClass = charClass(_image[i].character);
+      while ( ((left.x()>0) || (left.y()>0 && (_lineProperties[left.y()-1] & LINE_WRAPPED) )) 
+					  && charClass(_image[i-1].character) == selClass )
+      { i--; if (left.x()>0) left.rx()--; else {left.rx()=_usedColumns-1; left.ry()--;} }
+    }
+
+    // Find left (left_not_right ? from start : from here)
+    QPoint right = left_not_right ? _iPntSelCorr : here;
+    i = loc(right.x(),right.y());
+    if (i>=0 && i<=_imageSize) {
+      selClass = charClass(_image[i].character);
+      while( ((right.x()<_usedColumns-1) || (right.y()<_usedLines-1 && (_lineProperties[right.y()] & LINE_WRAPPED) )) 
+					  && charClass(_image[i+1].character) == selClass )
+      { i++; if (right.x()<_usedColumns-1) right.rx()++; else {right.rx()=0; right.ry()++; } }
+    }
+
+    // Pick which is start (ohere) and which is extension (here)
+    if ( left_not_right )
+    {
+      here = left; ohere = right;
+    }
+    else
+    {
+      here = right; ohere = left;
+    }
+    ohere.rx()++;
+  }
+
+  if ( _lineSelectionMode )
+  {
+    // Extend to complete line
+    bool above_not_below = ( here.y() < _iPntSelCorr.y() );
+
+    QPoint above = above_not_below ? here : _iPntSelCorr;
+    QPoint below = above_not_below ? _iPntSelCorr : here;
+
+    while (above.y()>0 && (_lineProperties[above.y()-1] & LINE_WRAPPED) )
+      above.ry()--;
+    while (below.y()<_usedLines-1 && (_lineProperties[below.y()] & LINE_WRAPPED) )
+      below.ry()++;
+
+    above.setX(0);
+    below.setX(_usedColumns-1);
+
+    // Pick which is start (ohere) and which is extension (here)
+    if ( above_not_below )
+    {
+      here = above; ohere = below;
+    }
+    else
+    {
+      here = below; ohere = above;
+    }
+
+    QPoint newSelBegin = QPoint( ohere.x(), ohere.y() );
+    swapping = !(_tripleSelBegin==newSelBegin);
+    _tripleSelBegin = newSelBegin;
+
+    ohere.rx()++;
+  }
+
+  int offset = 0;
+  if ( !_wordSelectionMode && !_lineSelectionMode )
+  {
+    int i;
+    int selClass;
+
+    bool left_not_right = ( here.y() < _iPntSelCorr.y() ||
+	   here.y() == _iPntSelCorr.y() && here.x() < _iPntSelCorr.x() );
+    bool old_left_not_right = ( _pntSelCorr.y() < _iPntSelCorr.y() ||
+	   _pntSelCorr.y() == _iPntSelCorr.y() && _pntSelCorr.x() < _iPntSelCorr.x() );
+    swapping = left_not_right != old_left_not_right;
+
+    // Find left (left_not_right ? from here : from start)
+    QPoint left = left_not_right ? here : _iPntSelCorr;
+
+    // Find left (left_not_right ? from start : from here)
+    QPoint right = left_not_right ? _iPntSelCorr : here;
+    if ( right.x() > 0 && !_columnSelectionMode )
+    {
+      i = loc(right.x(),right.y());
+      if (i>=0 && i<=_imageSize) {
+        selClass = charClass(_image[i-1].character);
+        if (selClass == ' ')
+        {
+          while ( right.x() < _usedColumns-1 && charClass(_image[i+1].character) == selClass && (right.y()<_usedLines-1) && 
+						  !(_lineProperties[right.y()] & LINE_WRAPPED))
+          { i++; right.rx()++; }
+          if (right.x() < _usedColumns-1)
+            right = left_not_right ? _iPntSelCorr : here;
+          else
+            right.rx()++;  // will be balanced later because of offset=-1;
+        }
+      }
+    }
+
+    // Pick which is start (ohere) and which is extension (here)
+    if ( left_not_right )
+    {
+      here = left; ohere = right; offset = 0;
+    }
+    else
+    {
+      here = right; ohere = left; offset = -1;
+    }
+  }
+
+  if ((here == _pntSelCorr) && (scroll == _scrollBar->value())) return; // not moved
+
+  if (here == ohere) return; // It's not left, it's not right.
+
+  if ( _actSel < 2 || swapping )
+  {
+    if ( _columnSelectionMode && !_lineSelectionMode && !_wordSelectionMode )
+    {
+        _screenWindow->setSelectionStart( ohere.x() , ohere.y() , true );
+    }
+    else
+    {
+        _screenWindow->setSelectionStart( ohere.x()-1-offset , ohere.y() , false );
+    }
+
+  }
+
+  _actSel = 2; // within selection
+  _pntSel = here;
+  _pntSel.ry() += _scrollBar->value();
+
+  if ( _columnSelectionMode && !_lineSelectionMode && !_wordSelectionMode )
+  {
+     _screenWindow->setSelectionEnd( here.x() , here.y() );
+  }
+  else
+  {
+     _screenWindow->setSelectionEnd( here.x()+offset , here.y() );
+  }
+
+}
+
+void TerminalDisplay::mouseReleaseEvent(QMouseEvent* ev)
+{
+    if ( !_screenWindow )
+        return;
+
+    int charLine;
+    int charColumn;
+    getCharacterPosition(ev->pos(),charLine,charColumn);
+
+  if ( ev->button() == Qt::LeftButton)
+  {
+    emit isBusySelecting(false); 
+    if(dragInfo.state == diPending)
+    {
+      // We had a drag event pending but never confirmed.  Kill selection
+       _screenWindow->clearSelection();
+      //emit clearSelectionSignal();
+    }
+    else
+    {
+      if ( _actSel > 1 )
+      {
+          setSelection(  _screenWindow->selectedText(_preserveLineBreaks)  );
+      }
+
+      _actSel = 0;
+
+      //FIXME: emits a release event even if the mouse is
+      //       outside the range. The procedure used in `mouseMoveEvent'
+      //       applies here, too.
+
+      if (!_mouseMarks && !(ev->modifiers() & Qt::ShiftModifier))
+        emit mouseSignal( 3, // release
+                        charColumn + 1,
+                        charLine + 1 +_scrollBar->value() -_scrollBar->maximum() , 0);
+    }
+    dragInfo.state = diNone;
+  }
+  
+  
+  if ( !_mouseMarks && 
+       ((ev->button() == Qt::RightButton && !(ev->modifiers() & Qt::ShiftModifier))
+                        || ev->button() == Qt::MidButton) ) 
+  {
+    emit mouseSignal( 3, 
+                      charColumn + 1, 
+                      charLine + 1 +_scrollBar->value() -_scrollBar->maximum() , 
+                      0);
+  }
+}
+
+void TerminalDisplay::getCharacterPosition(const QPoint& widgetPoint,int& line,int& column) const
+{
+
+    column = (widgetPoint.x() + _fontWidth/2 -contentsRect().left()-_leftMargin) / _fontWidth;
+    line = (widgetPoint.y()-contentsRect().top()-_topMargin) / _fontHeight;
+
+    if ( line < 0 )
+        line = 0;
+    if ( column < 0 )
+        column = 0;
+
+    if ( line >= _usedLines )
+        line = _usedLines-1;
+
+    // the column value returned can be equal to _usedColumns, which
+    // is the position just after the last character displayed in a line.
+    //
+    // this is required so that the user can select characters in the right-most
+    // column (or left-most for right-to-left input)
+    if ( column > _usedColumns )
+        column = _usedColumns;
+}
+
+void TerminalDisplay::updateLineProperties()
+{
+    if ( !_screenWindow ) 
+        return;
+
+    _lineProperties = _screenWindow->getLineProperties();    
+}
+
+void TerminalDisplay::mouseDoubleClickEvent(QMouseEvent* ev)
+{
+  if ( ev->button() != Qt::LeftButton) return;
+  if ( !_screenWindow ) return;
+
+  int charLine = 0;
+  int charColumn = 0;
+
+  getCharacterPosition(ev->pos(),charLine,charColumn);
+
+  QPoint pos(charColumn,charLine);
+
+  // pass on double click as two clicks.
+  if (!_mouseMarks && !(ev->modifiers() & Qt::ShiftModifier))
+  {
+    // Send just _ONE_ click event, since the first click of the double click
+    // was already sent by the click handler
+    emit mouseSignal( 0, 
+                      pos.x()+1, 
+                      pos.y()+1 +_scrollBar->value() -_scrollBar->maximum(),
+                      0 ); // left button
+    return;
+  }
+
+  _screenWindow->clearSelection();
+  QPoint bgnSel = pos;
+  QPoint endSel = pos;
+  int i = loc(bgnSel.x(),bgnSel.y());
+  _iPntSel = bgnSel;
+  _iPntSel.ry() += _scrollBar->value();
+
+  _wordSelectionMode = true;
+
+  // find word boundaries...
+  int selClass = charClass(_image[i].character);
+  {
+     // find the start of the word
+     int x = bgnSel.x();
+     while ( ((x>0) || (bgnSel.y()>0 && (_lineProperties[bgnSel.y()-1] & LINE_WRAPPED) )) 
+					 && charClass(_image[i-1].character) == selClass )
+     {  
+       i--; 
+       if (x>0) 
+           x--; 
+       else 
+       {
+           x=_usedColumns-1; 
+           bgnSel.ry()--;
+       } 
+     }
+
+     bgnSel.setX(x);
+     _screenWindow->setSelectionStart( bgnSel.x() , bgnSel.y() , false );
+
+     // find the end of the word
+     i = loc( endSel.x(), endSel.y() );
+     x = endSel.x();
+     while( ((x<_usedColumns-1) || (endSel.y()<_usedLines-1 && (_lineProperties[endSel.y()] & LINE_WRAPPED) )) 
+					 && charClass(_image[i+1].character) == selClass )
+     { 
+         i++; 
+         if (x<_usedColumns-1) 
+             x++; 
+         else 
+         {  
+             x=0; 
+             endSel.ry()++; 
+         } 
+     }
+
+     endSel.setX(x);
+
+     // In word selection mode don't select @ (64) if at end of word.
+     if ( ( QChar( _image[i].character ) == '@' ) && ( ( endSel.x() - bgnSel.x() ) > 0 ) )
+       endSel.setX( x - 1 );
+
+
+     _actSel = 2; // within selection
+     
+     _screenWindow->setSelectionEnd( endSel.x() , endSel.y() );
+    
+     setSelection( _screenWindow->selectedText(_preserveLineBreaks) ); 
+   }
+
+  _possibleTripleClick=true;
+
+  QTimer::singleShot(QApplication::doubleClickInterval(),this,
+                     SLOT(tripleClickTimeout()));
+}
+
+void TerminalDisplay::wheelEvent( QWheelEvent* ev )
+{
+  if (ev->orientation() != Qt::Vertical)
+    return;
+
+  if ( _mouseMarks )
+    _scrollBar->event(ev);
+  else
+  {
+    int charLine;
+    int charColumn;
+    getCharacterPosition( ev->pos() , charLine , charColumn );
+    
+    emit mouseSignal( ev->delta() > 0 ? 4 : 5, 
+                      charColumn + 1, 
+                      charLine + 1 +_scrollBar->value() -_scrollBar->maximum() , 
+                      0);
+  }
+}
+
+void TerminalDisplay::tripleClickTimeout()
+{
+  _possibleTripleClick=false;
+}
+
+void TerminalDisplay::mouseTripleClickEvent(QMouseEvent* ev)
+{
+  if ( !_screenWindow ) return;
+
+  int charLine;
+  int charColumn;
+  getCharacterPosition(ev->pos(),charLine,charColumn);
+  _iPntSel = QPoint(charColumn,charLine);
+
+  _screenWindow->clearSelection();
+
+  _lineSelectionMode = true;
+  _wordSelectionMode = false;
+
+  _actSel = 2; // within selection
+  emit isBusySelecting(true); // Keep it steady...
+
+  while (_iPntSel.y()>0 && (_lineProperties[_iPntSel.y()-1] & LINE_WRAPPED) )
+    _iPntSel.ry()--;
+  
+  if (_tripleClickMode == SelectForwardsFromCursor) {
+    // find word boundary start
+    int i = loc(_iPntSel.x(),_iPntSel.y());
+    int selClass = charClass(_image[i].character);
+    int x = _iPntSel.x();
+    
+    while ( ((x>0) || 
+             (_iPntSel.y()>0 && (_lineProperties[_iPntSel.y()-1] & LINE_WRAPPED) )
+            ) 
+            && charClass(_image[i-1].character) == selClass )
+    {
+        i--; 
+        if (x>0) 
+            x--; 
+        else 
+        {
+            x=_columns-1; 
+            _iPntSel.ry()--;
+        } 
+    }
+
+    _screenWindow->setSelectionStart( x , _iPntSel.y() , false );
+    _tripleSelBegin = QPoint( x, _iPntSel.y() );
+  }
+  else if (_tripleClickMode == SelectWholeLine) {
+    _screenWindow->setSelectionStart( 0 , _iPntSel.y() , false );
+    _tripleSelBegin = QPoint( 0, _iPntSel.y() );
+  }
+
+  while (_iPntSel.y()<_lines-1 && (_lineProperties[_iPntSel.y()] & LINE_WRAPPED) )
+    _iPntSel.ry()++;
+  
+  _screenWindow->setSelectionEnd( _columns - 1 , _iPntSel.y() );
+
+  setSelection(_screenWindow->selectedText(_preserveLineBreaks));
+
+  _iPntSel.ry() += _scrollBar->value();
+}
+
+
+bool TerminalDisplay::focusNextPrevChild( bool next )
+{
+  if (next)
+    return false; // This disables changing the active part in konqueror
+                  // when pressing Tab
+  return QWidget::focusNextPrevChild( next );
+}
+
+
+int TerminalDisplay::charClass(quint16 ch) const
+{
+    QChar qch=QChar(ch);
+    if ( qch.isSpace() ) return ' ';
+
+    if ( qch.isLetterOrNumber() || _wordCharacters.contains(qch, Qt::CaseInsensitive ) )
+    return 'a';
+
+    // Everything else is weird
+    return 1;
+}
+
+void TerminalDisplay::setWordCharacters(const QString& wc)
+{
+	_wordCharacters = wc;
+}
+
+void TerminalDisplay::setUsesMouse(bool on)
+{
+  _mouseMarks = on;
+  setCursor( _mouseMarks ? Qt::IBeamCursor : Qt::ArrowCursor );
+}
+bool TerminalDisplay::usesMouse() const
+{
+    return _mouseMarks;
+}
+
+/* ------------------------------------------------------------------------- */
+/*                                                                           */
+/*                               Clipboard                                   */
+/*                                                                           */
+/* ------------------------------------------------------------------------- */
+
+#undef KeyPress
+
+void TerminalDisplay::emitSelection(bool useXselection,bool appendReturn)
+{
+  if ( !_screenWindow ) 
+      return;
+
+  // Paste Clipboard by simulating keypress events
+  QString text = QApplication::clipboard()->text(useXselection ? QClipboard::Selection :
+                                                                 QClipboard::Clipboard);
+  if(appendReturn)
+    text.append("\r");
+  if ( ! text.isEmpty() )
+  {
+    text.replace("\n", "\r");
+    QKeyEvent e(QEvent::KeyPress, 0, Qt::NoModifier, text);
+    emit keyPressedSignal(&e); // expose as a big fat keypress event
+    
+    _screenWindow->clearSelection();
+  }
+}
+
+void TerminalDisplay::setSelection(const QString& t)
+{
+  QApplication::clipboard()->setText(t, QClipboard::Selection);
+}
+
+void TerminalDisplay::copyClipboard()
+{
+  if ( !_screenWindow )
+      return;
+
+  QString text = _screenWindow->selectedText(_preserveLineBreaks);
+  QApplication::clipboard()->setText(text);
+}
+
+void TerminalDisplay::pasteClipboard()
+{
+  emitSelection(false,false);
+}
+
+void TerminalDisplay::pasteSelection()
+{
+  emitSelection(true,false);
+}
+
+/* ------------------------------------------------------------------------- */
+/*                                                                           */
+/*                                Keyboard                                   */
+/*                                                                           */
+/* ------------------------------------------------------------------------- */
+
+void TerminalDisplay::setFlowControlWarningEnabled( bool enable )
+{
+	_flowControlWarningEnabled = enable;
+	
+	// if the dialog is currently visible and the flow control warning has 
+	// been disabled then hide the dialog
+	if (!enable)
+		outputSuspended(false);
+}
+
+void TerminalDisplay::keyPressEvent( QKeyEvent* event )
+{
+//qDebug("%s %d keyPressEvent and key is %d", __FILE__, __LINE__, event->key());
+
+    bool emitKeyPressSignal = true;
+
+    // XonXoff flow control
+    if (event->modifiers() & Qt::ControlModifier && _flowControlWarningEnabled)
+	{
+		if ( event->key() == Qt::Key_S ) {
+		//qDebug("%s %d keyPressEvent, output suspended", __FILE__, __LINE__);
+				emit flowControlKeyPressed(true /*output suspended*/);
+		}
+		else if ( event->key() == Qt::Key_Q ) {
+		//qDebug("%s %d keyPressEvent, output enabled", __FILE__, __LINE__);
+				emit flowControlKeyPressed(false /*output enabled*/);
+		}
+	}
+
+    // Keyboard-based navigation
+    if ( event->modifiers() == Qt::ShiftModifier )
+    {
+        bool update = true;
+
+        if ( event->key() == Qt::Key_PageUp )
+        {
+	    //qDebug("%s %d pageup", __FILE__, __LINE__);
+            _screenWindow->scrollBy( ScreenWindow::ScrollPages , -1 );
+        }
+        else if ( event->key() == Qt::Key_PageDown )
+        {
+	    //qDebug("%s %d pagedown", __FILE__, __LINE__);
+            _screenWindow->scrollBy( ScreenWindow::ScrollPages , 1 );
+        }
+        else if ( event->key() == Qt::Key_Up )
+        {
+	    //qDebug("%s %d keyup", __FILE__, __LINE__);	
+            _screenWindow->scrollBy( ScreenWindow::ScrollLines , -1 );
+        }
+        else if ( event->key() == Qt::Key_Down )
+        {
+	    //qDebug("%s %d keydown", __FILE__, __LINE__);	
+            _screenWindow->scrollBy( ScreenWindow::ScrollLines , 1 );
+        }
+        else {
+            update = false;
+	}
+
+        if ( update )
+        {
+	    //qDebug("%s %d updating", __FILE__, __LINE__);	
+            _screenWindow->setTrackOutput( _screenWindow->atEndOfOutput() );
+            
+            updateLineProperties();
+            updateImage();
+
+            // do not send key press to terminal
+            emitKeyPressSignal = false;
+        }
+    }
+    
+    _screenWindow->setTrackOutput( true );
+    
+    _actSel=0; // Key stroke implies a screen update, so TerminalDisplay won't
+              // know where the current selection is.
+
+    if (_hasBlinkingCursor) 
+    {
+      _blinkCursorTimer->start(BLINK_DELAY);
+      if (_cursorBlinking)
+        blinkCursorEvent();
+      else
+        _cursorBlinking = false;
+    }
+
+    if ( emitKeyPressSignal )
+        emit keyPressedSignal(event);
+
+    event->accept();
+}
+
+void TerminalDisplay::inputMethodEvent( QInputMethodEvent* event )
+{
+    QKeyEvent keyEvent(QEvent::KeyPress,0,Qt::NoModifier,event->commitString());
+    emit keyPressedSignal(&keyEvent);
+
+    _inputMethodData.preeditString = event->preeditString();
+    update(preeditRect() | _inputMethodData.previousPreeditRect);
+    
+    event->accept();
+}
+QVariant TerminalDisplay::inputMethodQuery( Qt::InputMethodQuery query ) const
+{
+    const QPoint cursorPos = _screenWindow ? _screenWindow->cursorPosition() : QPoint(0,0);
+    switch ( query ) 
+    {
+        case Qt::ImMicroFocus:
+                return imageToWidget(QRect(cursorPos.x(),cursorPos.y(),1,1));
+            break;
+        case Qt::ImFont:
+                return font();
+            break;
+        case Qt::ImCursorPosition:
+                // return the cursor position within the current line
+                return cursorPos.x();
+            break;
+        case Qt::ImSurroundingText:
+            {
+                // return the text from the current line
+                QString lineText;
+                QTextStream stream(&lineText);
+                PlainTextDecoder decoder;
+                decoder.begin(&stream);
+                decoder.decodeLine(&_image[loc(0,cursorPos.y())],_usedColumns,_lineProperties[cursorPos.y()]);
+                decoder.end();
+                return lineText;
+            }
+            break;
+        case Qt::ImCurrentSelection:
+                return QString();
+            break;
+    }
+
+    return QVariant();
+}
+
+bool TerminalDisplay::event( QEvent *e )
+{
+  if ( e->type() == QEvent::ShortcutOverride )
+  {
+    QKeyEvent* keyEvent = static_cast<QKeyEvent *>( e );
+
+    // a check to see if keyEvent->text() is empty is used
+    // to avoid intercepting the press of the modifier key on its own.
+    //
+    // this is important as it allows a press and release of the Alt key
+    // on its own to focus the menu bar, making it possible to
+    // work with the menu without using the mouse
+    if ( (keyEvent->modifiers() == Qt::AltModifier) && 
+         !keyEvent->text().isEmpty() )
+    {
+    	keyEvent->accept();
+      	return true;
+    }
+
+    // Override any of the following shortcuts because
+    // they are needed by the terminal
+    int keyCode = keyEvent->key() | keyEvent->modifiers();
+    switch ( keyCode )
+    {
+      // list is taken from the QLineEdit::event() code
+      case Qt::Key_Tab:
+      case Qt::Key_Delete:
+      case Qt::Key_Home:
+      case Qt::Key_End:
+      case Qt::Key_Backspace:
+      case Qt::Key_Left:
+      case Qt::Key_Right:
+        keyEvent->accept();
+        return true;
+    }
+  }
+  return QWidget::event( e );
+}
+
+void TerminalDisplay::setBellMode(int mode)
+{
+  _bellMode=mode;
+}
+
+void TerminalDisplay::enableBell()
+{
+    _allowBell = true;
+}
+
+void TerminalDisplay::bell(const QString&)
+{
+  if (_bellMode==NoBell) return;
+
+  //limit the rate at which bells can occur 
+  //...mainly for sound effects where rapid bells in sequence 
+  //produce a horrible noise
+  if ( _allowBell )
+  {
+    _allowBell = false;
+    QTimer::singleShot(500,this,SLOT(enableBell()));
+ 
+    if (_bellMode==SystemBeepBell) 
+    {
+//        KNotification::beep();
+    } 
+    else if (_bellMode==NotifyBell) 
+    {
+//        KNotification::event("BellVisible", message,QPixmap(),this);
+    } 
+    else if (_bellMode==VisualBell) 
+    {
+        swapColorTable();
+        QTimer::singleShot(200,this,SLOT(swapColorTable()));
+    }
+  }
+}
+
+void TerminalDisplay::swapColorTable()
+{
+  ColorEntry color = _colorTable[1];
+  _colorTable[1]=_colorTable[0];
+  _colorTable[0]= color;
+  _colorsInverted = !_colorsInverted;
+  update();
+}
+
+void TerminalDisplay::clearImage()
+{
+  // We initialize _image[_imageSize] too. See makeImage()
+  for (int i = 0; i <= _imageSize; i++)
+  {
+    _image[i].character = ' ';
+    _image[i].foregroundColor = CharacterColor(COLOR_SPACE_DEFAULT,
+                                               DEFAULT_FORE_COLOR);
+    _image[i].backgroundColor = CharacterColor(COLOR_SPACE_DEFAULT,
+                                               DEFAULT_BACK_COLOR);
+    _image[i].rendition = DEFAULT_RENDITION;
+  }
+}
+
+void TerminalDisplay::calcGeometry()
+{
+  _scrollBar->resize(QApplication::style()->pixelMetric(QStyle::PM_ScrollBarExtent),
+                    contentsRect().height());
+  switch(_scrollbarLocation)
+  {
+    case NoScrollBar :
+     _leftMargin = DEFAULT_LEFT_MARGIN;
+     _contentWidth = contentsRect().width() - 2 * DEFAULT_LEFT_MARGIN;
+     break;
+    case ScrollBarLeft :
+     _leftMargin = DEFAULT_LEFT_MARGIN + _scrollBar->width();
+     _contentWidth = contentsRect().width() - 2 * DEFAULT_LEFT_MARGIN - _scrollBar->width();
+     _scrollBar->move(contentsRect().topLeft());
+     break;
+    case ScrollBarRight:
+     _leftMargin = DEFAULT_LEFT_MARGIN;
+     _contentWidth = contentsRect().width()  - 2 * DEFAULT_LEFT_MARGIN - _scrollBar->width();
+     _scrollBar->move(contentsRect().topRight() - QPoint(_scrollBar->width()-1,0));
+     break;
+  }
+
+  _topMargin = DEFAULT_TOP_MARGIN;
+  _contentHeight = contentsRect().height() - 2 * DEFAULT_TOP_MARGIN + /* mysterious */ 1;
+
+  if (!_isFixedSize)
+  {
+     // ensure that display is always at least one column wide
+     _columns = qMax(1,_contentWidth / _fontWidth);
+     _usedColumns = qMin(_usedColumns,_columns);
+     
+     // ensure that display is always at least one line high
+     _lines = qMax(1,_contentHeight / _fontHeight);
+     _usedLines = qMin(_usedLines,_lines);
+  }
+}
+
+void TerminalDisplay::makeImage()
+{
+//qDebug("%s %d makeImage", __FILE__, __LINE__);
+  calcGeometry();
+
+  // confirm that array will be of non-zero size, since the painting code 
+  // assumes a non-zero array length
+  Q_ASSERT( _lines > 0 && _columns > 0 );
+  Q_ASSERT( _usedLines <= _lines && _usedColumns <= _columns );
+
+  _imageSize=_lines*_columns;
+  
+  // We over-commit one character so that we can be more relaxed in dealing with
+  // certain boundary conditions: _image[_imageSize] is a valid but unused position
+  _image = new Character[_imageSize+1];
+
+  clearImage();
+}
+
+// calculate the needed size
+void TerminalDisplay::setSize(int columns, int lines)
+{
+  //FIXME - Not quite correct, a small amount of additional space
+  // will be used for margins, the scrollbar etc.
+  // we need to allow for this so that '_size' does allow
+  // enough room for the specified number of columns and lines to fit
+
+  QSize newSize = QSize( columns * _fontWidth  ,
+				 lines * _fontHeight   );
+
+  if ( newSize != size() )
+  {
+    _size = newSize;
+    updateGeometry();
+  }
+}
+
+void TerminalDisplay::setFixedSize(int cols, int lins)
+{
+  _isFixedSize = true;
+  
+  //ensure that display is at least one line by one column in size
+  _columns = qMax(1,cols);
+  _lines = qMax(1,lins);
+  _usedColumns = qMin(_usedColumns,_columns);
+  _usedLines = qMin(_usedLines,_lines);
+
+  if (_image)
+  {
+     delete[] _image;
+     makeImage();
+  }
+  setSize(cols, lins);
+  QWidget::setFixedSize(_size);
+}
+
+QSize TerminalDisplay::sizeHint() const
+{
+  return _size;
+}
+
+
+/* --------------------------------------------------------------------- */
+/*                                                                       */
+/* Drag & Drop                                                           */
+/*                                                                       */
+/* --------------------------------------------------------------------- */
+
+void TerminalDisplay::dragEnterEvent(QDragEnterEvent* event)
+{
+  if (event->mimeData()->hasFormat("text/plain"))
+      event->acceptProposedAction();
+}
+
+void TerminalDisplay::dropEvent(QDropEvent* event)
+{
+//  KUrl::List urls = KUrl::List::fromMimeData(event->mimeData());
+
+  QString dropText;
+/*  if (!urls.isEmpty()) 
+  {
+    for ( int i = 0 ; i < urls.count() ; i++ ) 
+    {
+        KUrl url = KIO::NetAccess::mostLocalUrl( urls[i] , 0 );
+        QString urlText;
+
+        if (url.isLocalFile())
+            urlText = url.path(); 
+        else
+            urlText = url.url();
+    
+        // in future it may be useful to be able to insert file names with drag-and-drop
+        // without quoting them (this only affects paths with spaces in) 
+        urlText = KShell::quoteArg(urlText);
+      
+        dropText += urlText;
+
+        if ( i != urls.count()-1 ) 
+            dropText += ' ';
+    }
+  }
+  else 
+  {
+    dropText = event->mimeData()->text();
+  }
+*/
+  if(event->mimeData()->hasFormat("text/plain")) 
+  {
+    emit sendStringToEmu(dropText.toLocal8Bit());
+  }
+}
+
+void TerminalDisplay::doDrag()
+{
+  dragInfo.state = diDragging;
+  dragInfo.dragObject = new QDrag(this);
+  QMimeData *mimeData = new QMimeData;
+  mimeData->setText(QApplication::clipboard()->text(QClipboard::Selection));
+  dragInfo.dragObject->setMimeData(mimeData);
+  dragInfo.dragObject->start(Qt::CopyAction);
+  // Don't delete the QTextDrag object.  Qt will delete it when it's done with it.
+}
+
+void TerminalDisplay::outputSuspended(bool suspended)
+{
+	//create the label when this function is first called
+	if (!_outputSuspendedLabel)
+	{
+            //This label includes a link to an English language website
+            //describing the 'flow control' (Xon/Xoff) feature found in almost 
+            //all terminal emulators.
+            //If there isn't a suitable article available in the target language the link
+            //can simply be removed.
+			_outputSuspendedLabel = new QLabel( ("<qt>Output has been "
+                                                "<a href=\"http://en.wikipedia.org/wiki/XON\">suspended</a>"
+                                                " by pressing Ctrl+S."
+											   "  Press <b>Ctrl+Q</b> to resume.</qt>"),
+											   this );
+
+            QPalette palette(_outputSuspendedLabel->palette());
+	    
+	    palette.setColor(QPalette::Normal, QPalette::WindowText, QColor(Qt::white));
+	    palette.setColor(QPalette::Normal, QPalette::Window, QColor(Qt::black));
+//            KColorScheme::adjustForeground(palette,KColorScheme::NeutralText);
+//		KColorScheme::adjustBackground(palette,KColorScheme::NeutralBackground);
+    	    _outputSuspendedLabel->setPalette(palette);
+	    _outputSuspendedLabel->setAutoFillBackground(true);
+	    _outputSuspendedLabel->setBackgroundRole(QPalette::Base);
+	    _outputSuspendedLabel->setFont(QApplication::font());
+            _outputSuspendedLabel->setMargin(5);
+
+            //enable activation of "Xon/Xoff" link in label
+            _outputSuspendedLabel->setTextInteractionFlags(Qt::LinksAccessibleByMouse | 
+                                                          Qt::LinksAccessibleByKeyboard);
+            _outputSuspendedLabel->setOpenExternalLinks(true);
+            _outputSuspendedLabel->setVisible(false);
+
+            _gridLayout->addWidget(_outputSuspendedLabel);       
+            _gridLayout->addItem( new QSpacerItem(0,0,QSizePolicy::Expanding,
+                                                      QSizePolicy::Expanding),
+                                 1,0);
+
+    }
+
+	_outputSuspendedLabel->setVisible(suspended);
+}
+
+uint TerminalDisplay::lineSpacing() const
+{
+  return _lineSpacing;
+}
+
+void TerminalDisplay::setLineSpacing(uint i)
+{
+  _lineSpacing = i;
+  setVTFont(font()); // Trigger an update.
+}
+
+//#include "moc_TerminalDisplay.cpp"
new file mode 100644
--- /dev/null
+++ b/gui//TerminalDisplay.h
@@ -0,0 +1,754 @@
+/*
+    Copyright (C) 2007 by Robert Knight <robertknight@gmail.com>
+    Copyright (C) 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
+
+    Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301  USA.
+*/
+
+#ifndef TERMINALDISPLAY_H
+#define TERMINALDISPLAY_H
+
+// Qt
+#include <QtGui/QColor>
+#include <QtCore/QPointer>
+#include <QtGui/QWidget>
+
+// Konsole
+#include "Filter.h"
+#include "Character.h"
+#include "ColorTables.h"
+
+class QDrag;
+class QDragEnterEvent;
+class QDropEvent;
+class QLabel;
+class QTimer;
+class QEvent;
+class QFrame;
+class QGridLayout;
+class QKeyEvent;
+class QScrollBar;
+class QShowEvent;
+class QHideEvent;
+class QWidget;
+
+//class KMenu;
+
+namespace Konsole
+{
+
+extern unsigned short vt100_graphics[32];
+
+class ScreenWindow;
+
+/**
+ * A widget which displays output from a terminal emulation and sends input keypresses and mouse activity
+ * to the terminal.
+ *
+ * When the terminal emulation receives new output from the program running in the terminal, 
+ * it will update the display by calling updateImage().
+ *
+ * TODO More documentation
+ */
+class TerminalDisplay : public QWidget
+{
+   Q_OBJECT
+
+public:
+    /** Constructs a new terminal display widget with the specified parent. */
+    TerminalDisplay(QWidget *parent=0);
+    virtual ~TerminalDisplay();
+
+    /** Returns the terminal color palette used by the display. */
+    const ColorEntry* colorTable() const;
+    /** Sets the terminal color palette used by the display. */
+    void setColorTable(const ColorEntry table[]);
+    /**
+     * Sets the seed used to generate random colors for the display
+     * (in color schemes that support them).
+     */
+    void setRandomSeed(uint seed);
+    /**
+     * Returns the seed used to generate random colors for the display
+     * (in color schemes that support them).
+     */
+    uint randomSeed() const;
+
+    /** Sets the opacity of the terminal display. */
+    void setOpacity(qreal opacity);
+
+    /** 
+     * This enum describes the location where the scroll bar is positioned in the display widget.
+     */
+    enum ScrollBarPosition 
+    { 
+        /** Do not show the scroll bar. */
+        NoScrollBar=0, 
+        /** Show the scroll bar on the left side of the display. */
+        ScrollBarLeft=1, 
+        /** Show the scroll bar on the right side of the display. */
+        ScrollBarRight=2 
+    };
+    /** 
+     * Specifies whether the terminal display has a vertical scroll bar, and if so whether it
+     * is shown on the left or right side of the display.
+     */
+    void setScrollBarPosition(ScrollBarPosition position);
+
+    /** 
+     * Sets the current position and range of the display's scroll bar.
+     *
+     * @param cursor The position of the scroll bar's thumb.
+     * @param lines The maximum value of the scroll bar.
+     */
+    void setScroll(int cursor, int lines);
+
+    /** 
+     * Returns the display's filter chain.  When the image for the display is updated,
+     * the text is passed through each filter in the chain.  Each filter can define
+     * hotspots which correspond to certain strings (such as URLs or particular words).
+     * Depending on the type of the hotspots created by the filter ( returned by Filter::Hotspot::type() )
+     * the view will draw visual cues such as underlines on mouse-over for links or translucent
+     * rectangles for markers.
+     *
+     * To add a new filter to the view, call:
+     *      viewWidget->filterChain()->addFilter( filterObject );
+     */
+    FilterChain* filterChain() const;
+
+    /** 
+     * Updates the filters in the display's filter chain.  This will cause
+     * the hotspots to be updated to match the current image.
+     *
+     * WARNING:  This function can be expensive depending on the 
+     * image size and number of filters in the filterChain()
+     *
+     * TODO - This API does not really allow efficient usage.  Revise it so
+     * that the processing can be done in a better way.
+     *
+     * eg:
+     *      - Area of interest may be known ( eg. mouse cursor hovering
+     *      over an area )
+     */  
+    void processFilters();
+
+    /** 
+     * Returns a list of menu actions created by the filters for the content
+     * at the given @p position.
+     */
+    QList<QAction*> filterActions(const QPoint& position);
+
+    /** Returns true if the cursor is set to blink or false otherwise. */
+    bool blinkingCursor() { return _hasBlinkingCursor; }
+    /** Specifies whether or not the cursor blinks. */
+    void setBlinkingCursor(bool blink);
+
+    void setCtrlDrag(bool enable) { _ctrlDrag=enable; }
+    bool ctrlDrag() { return _ctrlDrag; }
+
+	/** 
+     *  This enum describes the methods for selecting text when
+ 	 *  the user triple-clicks within the display. 
+ 	 */
+	enum TripleClickMode
+	{
+		/** Select the whole line underneath the cursor. */
+		SelectWholeLine,
+		/** Select from the current cursor position to the end of the line. */
+		SelectForwardsFromCursor
+	};
+    /** Sets how the text is selected when the user triple clicks within the display. */	
+    void setTripleClickMode(TripleClickMode mode) { _tripleClickMode = mode; }
+	/** See setTripleClickSelectionMode() */
+    TripleClickMode tripleClickMode() { return _tripleClickMode; }
+
+    void setLineSpacing(uint);
+    uint lineSpacing() const;
+
+    void emitSelection(bool useXselection,bool appendReturn);
+
+    /**
+     * This enum describes the available shapes for the keyboard cursor.
+     * See setKeyboardCursorShape()
+     */
+    enum KeyboardCursorShape
+    {
+        /** A rectangular block which covers the entire area of the cursor character. */
+        BlockCursor,
+        /** 
+         * A single flat line which occupies the space at the bottom of the cursor
+         * character's area.
+         */
+        UnderlineCursor,
+        /** 
+         * An cursor shaped like the capital letter 'I', similar to the IBeam 
+         * cursor used in Qt/KDE text editors.
+         */
+        IBeamCursor
+    };
+    /** 
+     * Sets the shape of the keyboard cursor.  This is the cursor drawn   
+     * at the position in the terminal where keyboard input will appear.
+     *
+     * In addition the terminal display widget also has a cursor for 
+     * the mouse pointer, which can be set using the QWidget::setCursor()
+     * method.
+     *
+     * Defaults to BlockCursor
+     */
+    void setKeyboardCursorShape(KeyboardCursorShape shape);
+    /**
+     * Returns the shape of the keyboard cursor.  See setKeyboardCursorShape()
+     */
+    KeyboardCursorShape keyboardCursorShape() const;
+
+    /**
+     * Sets the color used to draw the keyboard cursor.  
+     *
+     * The keyboard cursor defaults to using the foreground color of the character
+     * underneath it.
+     *
+     * @param useForegroundColor If true, the cursor color will change to match
+     * the foreground color of the character underneath it as it is moved, in this
+     * case, the @p color parameter is ignored and the color of the character
+     * under the cursor is inverted to ensure that it is still readable.
+     * @param color The color to use to draw the cursor.  This is only taken into
+     * account if @p useForegroundColor is false.
+     */
+    void setKeyboardCursorColor(bool useForegroundColor , const QColor& color);
+
+    /** 
+     * Returns the color of the keyboard cursor, or an invalid color if the keyboard
+     * cursor color is set to change according to the foreground color of the character
+     * underneath it. 
+     */
+    QColor keyboardCursorColor() const;
+
+    /**
+     * Returns the number of lines of text which can be displayed in the widget.
+     *
+     * This will depend upon the height of the widget and the current font.
+     * See fontHeight()
+     */
+    int  lines()   { return _lines;   }
+    /**
+     * Returns the number of characters of text which can be displayed on
+     * each line in the widget.
+     *
+     * This will depend upon the width of the widget and the current font.
+     * See fontWidth()
+     */
+    int  columns() { return _columns; }
+
+    /**
+     * Returns the height of the characters in the font used to draw the text in the display.
+     */
+    int  fontHeight()   { return _fontHeight;   }
+    /**
+     * Returns the width of the characters in the display.  
+     * This assumes the use of a fixed-width font.
+     */
+    int  fontWidth()    { return _fontWidth; }
+
+    void setSize(int cols, int lins);
+    void setFixedSize(int cols, int lins);
+    
+    // reimplemented
+    QSize sizeHint() const;
+
+    /**
+     * Sets which characters, in addition to letters and numbers, 
+     * are regarded as being part of a word for the purposes
+     * of selecting words in the display by double clicking on them.
+     *
+     * The word boundaries occur at the first and last characters which
+     * are either a letter, number, or a character in @p wc
+     *
+     * @param wc An array of characters which are to be considered parts
+     * of a word ( in addition to letters and numbers ).
+     */
+    void setWordCharacters(const QString& wc);
+    /** 
+     * Returns the characters which are considered part of a word for the 
+     * purpose of selecting words in the display with the mouse.
+     *
+     * @see setWordCharacters()
+     */
+    QString wordCharacters() { return _wordCharacters; }
+
+    /** 
+     * Sets the type of effect used to alert the user when a 'bell' occurs in the 
+     * terminal session.
+     *
+     * The terminal session can trigger the bell effect by calling bell() with
+     * the alert message.
+     */
+    void setBellMode(int mode);
+    /** 
+     * Returns the type of effect used to alert the user when a 'bell' occurs in
+     * the terminal session.
+     * 
+     * See setBellMode()
+     */
+    int bellMode() { return _bellMode; }
+
+    /**
+     * This enum describes the different types of sounds and visual effects which
+     * can be used to alert the user when a 'bell' occurs in the terminal
+     * session.
+     */
+    enum BellMode
+    { 
+        /** A system beep. */
+        SystemBeepBell=0, 
+        /** 
+         * KDE notification.  This may play a sound, show a passive popup
+         * or perform some other action depending on the user's settings.
+         */
+        NotifyBell=1, 
+        /** A silent, visual bell (eg. inverting the display's colors briefly) */
+        VisualBell=2, 
+        /** No bell effects */
+        NoBell=3 
+    };
+
+    void setSelection(const QString &t);
+
+    /** 
+     * Reimplemented.  Has no effect.  Use setVTFont() to change the font
+     * used to draw characters in the display.
+     */
+    virtual void setFont(const QFont &);
+
+    /** Returns the font used to draw characters in the display */
+    QFont getVTFont() { return font(); }
+
+    /** 
+     * Sets the font used to draw the display.  Has no effect if @p font
+     * is larger than the size of the display itself.    
+     */
+    void setVTFont(const QFont& font);
+
+    /**
+     * Specified whether anti-aliasing of text in the terminal display
+     * is enabled or not.  Defaults to enabled.
+     */
+    static void setAntialias( bool antialias ) { _antialiasText = antialias; }
+    /** 
+     * Returns true if anti-aliasing of text in the terminal is enabled.
+     */
+    static bool antialias()                 { return _antialiasText;   }
+    
+    /**
+     * Sets whether or not the current height and width of the 
+     * terminal in lines and columns is displayed whilst the widget
+     * is being resized.
+     */
+    void setTerminalSizeHint(bool on) { _terminalSizeHint=on; }
+    /** 
+     * Returns whether or not the current height and width of
+     * the terminal in lines and columns is displayed whilst the widget
+     * is being resized.
+     */
+    bool terminalSizeHint() { return _terminalSizeHint; }
+    /** 
+     * Sets whether the terminal size display is shown briefly
+     * after the widget is first shown.
+     *
+     * See setTerminalSizeHint() , isTerminalSizeHint()
+     */
+    void setTerminalSizeStartup(bool on) { _terminalSizeStartup=on; }
+
+    void setBidiEnabled(bool set) { _bidiEnabled=set; }
+    bool isBidiEnabled() { return _bidiEnabled; }
+
+    /**
+     * Sets the terminal screen section which is displayed in this widget.
+     * When updateImage() is called, the display fetches the latest character image from the
+     * the associated terminal screen window.
+     *
+     * In terms of the model-view paradigm, the ScreenWindow is the model which is rendered
+     * by the TerminalDisplay.
+     */
+    void setScreenWindow( ScreenWindow* window );
+    /** Returns the terminal screen section which is displayed in this widget.  See setScreenWindow() */
+    ScreenWindow* screenWindow() const;
+
+    static bool HAVE_TRANSPARENCY;
+
+public slots:
+
+    /** 
+     * Causes the terminal display to fetch the latest character image from the associated
+     * terminal screen ( see setScreenWindow() ) and redraw the display.
+     */
+    void updateImage(); 
+    /**
+     * Causes the terminal display to fetch the latest line status flags from the 
+     * associated terminal screen ( see setScreenWindow() ).  
+     */ 
+    void updateLineProperties();
+
+    /** Copies the selected text to the clipboard. */
+    void copyClipboard();
+    /** 
+     * Pastes the content of the clipboard into the 
+     * display.
+     */
+    void pasteClipboard();
+    /**
+     * Pastes the content of the selection into the
+     * display.
+     */
+    void pasteSelection();
+
+	/** 
+ 	  * Changes whether the flow control warning box should be shown when the flow control
+ 	  * stop key (Ctrl+S) are pressed.
+ 	  */
+	void setFlowControlWarningEnabled(bool enabled);
+	
+    /** 
+	 * Causes the widget to display or hide a message informing the user that terminal
+	 * output has been suspended (by using the flow control key combination Ctrl+S)
+	 *
+	 * @param suspended True if terminal output has been suspended and the warning message should
+	 *				 	be shown or false to indicate that terminal output has been resumed and that
+	 *				 	the warning message should disappear.
+	 */ 
+	void outputSuspended(bool suspended);
+
+    /**
+     * Sets whether the program whoose output is being displayed in the view
+     * is interested in mouse events.
+     *
+     * If this is set to true, mouse signals will be emitted by the view when the user clicks, drags
+     * or otherwise moves the mouse inside the view.
+     * The user interaction needed to create selections will also change, and the user will be required
+     * to hold down the shift key to create a selection or perform other mouse activities inside the 
+     * view area - since the program running in the terminal is being allowed to handle normal mouse
+     * events itself.
+     *
+     * @param usesMouse Set to true if the program running in the terminal is interested in mouse events
+     * or false otherwise.
+     */
+    void setUsesMouse(bool usesMouse);
+  
+    /** See setUsesMouse() */
+    bool usesMouse() const;
+
+    /** 
+     * Shows a notification that a bell event has occurred in the terminal.
+     * TODO: More documentation here
+     */
+    void bell(const QString& message);
+
+signals:
+
+    /**
+     * Emitted when the user presses a key whilst the terminal widget has focus.
+     */
+    void keyPressedSignal(QKeyEvent *e);
+
+    /**
+     * Emitted when the user presses the suspend or resume flow control key combinations 
+     * 
+     * @param suspend true if the user pressed Ctrl+S (the suspend output key combination) or
+     * false if the user pressed Ctrl+Q (the resume output key combination)
+     */
+    void flowControlKeyPressed(bool suspend);
+    
+    /** 
+     * A mouse event occurred.
+     * @param button The mouse button (0 for left button, 1 for middle button, 2 for right button, 3 for release)
+     * @param column The character column where the event occurred
+     * @param line The character row where the event occurred
+     * @param eventType The type of event.  0 for a mouse press / release or 1 for mouse motion
+     */
+    void mouseSignal(int button, int column, int line, int eventType);
+    void changedFontMetricSignal(int height, int width);
+    void changedContentSizeSignal(int height, int width);
+
+    /** 
+     * Emitted when the user right clicks on the display, or right-clicks with the Shift
+     * key held down if usesMouse() is true.
+     *
+     * This can be used to display a context menu.
+     */
+    void configureRequest( TerminalDisplay*, int state, const QPoint& position );
+
+   void isBusySelecting(bool);
+   void sendStringToEmu(const char*);
+
+protected:
+    virtual bool event( QEvent * );
+
+    virtual void paintEvent( QPaintEvent * );
+
+    virtual void showEvent(QShowEvent*);
+    virtual void hideEvent(QHideEvent*);
+    virtual void resizeEvent(QResizeEvent*);
+
+    virtual void fontChange(const QFont &font);
+
+    virtual void keyPressEvent(QKeyEvent* event);
+    virtual void mouseDoubleClickEvent(QMouseEvent* ev);
+    virtual void mousePressEvent( QMouseEvent* );
+    virtual void mouseReleaseEvent( QMouseEvent* );
+    virtual void mouseMoveEvent( QMouseEvent* );
+    virtual void extendSelection( const QPoint& pos );
+    virtual void wheelEvent( QWheelEvent* );
+
+    virtual bool focusNextPrevChild( bool next );
+    
+    // drag and drop
+    virtual void dragEnterEvent(QDragEnterEvent* event);
+    virtual void dropEvent(QDropEvent* event);
+    void doDrag();
+    enum DragState { diNone, diPending, diDragging };
+
+    struct _dragInfo {
+      DragState       state;
+      QPoint          start;
+      QDrag           *dragObject;
+    } dragInfo;
+
+    virtual int charClass(quint16) const;
+
+    void clearImage();
+
+    void mouseTripleClickEvent(QMouseEvent* ev);
+
+    // reimplemented
+    virtual void inputMethodEvent ( QInputMethodEvent* event );
+    virtual QVariant inputMethodQuery( Qt::InputMethodQuery query ) const;
+
+protected slots:
+
+    void scrollBarPositionChanged(int value);
+    void blinkEvent();
+    void blinkCursorEvent();
+    
+    //Renables bell noises and visuals.  Used to disable further bells for a short period of time
+    //after emitting the first in a sequence of bell events.
+    void enableBell();
+
+private slots:
+
+    void swapColorTable();
+    void tripleClickTimeout();  // resets possibleTripleClick
+
+private:
+
+    // -- Drawing helpers --
+
+    // divides the part of the display specified by 'rect' into
+    // fragments according to their colors and styles and calls
+    // drawTextFragment() to draw the fragments 
+    void drawContents(QPainter &paint, const QRect &rect);
+    // draws a section of text, all the text in this section
+    // has a common color and style
+    void drawTextFragment(QPainter& painter, const QRect& rect, 
+                          const QString& text, const Character* style); 
+    // draws the background for a text fragment
+    // if useOpacitySetting is true then the color's alpha value will be set to
+    // the display's transparency (set with setOpacity()), otherwise the background
+    // will be drawn fully opaque
+    void drawBackground(QPainter& painter, const QRect& rect, const QColor& color,
+						bool useOpacitySetting);
+    // draws the cursor character
+    void drawCursor(QPainter& painter, const QRect& rect , const QColor& foregroundColor, 
+                                       const QColor& backgroundColor , bool& invertColors);
+    // draws the characters or line graphics in a text fragment
+    void drawCharacters(QPainter& painter, const QRect& rect,  const QString& text, 
+                                           const Character* style, bool invertCharacterColor);
+    // draws a string of line graphics
+	void drawLineCharString(QPainter& painter, int x, int y, 
+                            const QString& str, const Character* attributes);
+
+    // draws the preedit string for input methods
+    void drawInputMethodPreeditString(QPainter& painter , const QRect& rect);
+
+    // --
+
+    // maps an area in the character image to an area on the widget 
+    QRect imageToWidget(const QRect& imageArea) const;
+
+    // maps a point on the widget to the position ( ie. line and column ) 
+    // of the character at that point.
+    void getCharacterPosition(const QPoint& widgetPoint,int& line,int& column) const;
+
+    // the area where the preedit string for input methods will be draw
+    QRect preeditRect() const;
+
+    // shows a notification window in the middle of the widget indicating the terminal's
+    // current size in columns and lines
+    void showResizeNotification();
+
+    // scrolls the image by a number of lines.  
+    // 'lines' may be positive ( to scroll the image down ) 
+    // or negative ( to scroll the image up )
+    // 'region' is the part of the image to scroll - currently only
+    // the top, bottom and height of 'region' are taken into account,
+    // the left and right are ignored.
+    void scrollImage(int lines , const QRect& region);
+
+    void calcGeometry();
+    void propagateSize();
+    void updateImageSize();
+    void makeImage();
+    
+    void paintFilters(QPainter& painter);
+
+	// returns a region covering all of the areas of the widget which contain
+	// a hotspot
+	QRegion hotSpotRegion() const;
+
+	// returns the position of the cursor in columns and lines
+	QPoint cursorPosition() const;
+
+    // the window onto the terminal screen which this display
+    // is currently showing.  
+    QPointer<ScreenWindow> _screenWindow;
+
+    bool _allowBell;
+
+    QGridLayout* _gridLayout;
+
+    bool _fixedFont; // has fixed pitch
+    int  _fontHeight;     // height
+    int  _fontWidth;     // width
+    int  _fontAscent;     // ascend
+
+    int _leftMargin;    // offset
+    int _topMargin;    // offset
+
+    int _lines;      // the number of lines that can be displayed in the widget
+    int _columns;    // the number of columns that can be displayed in the widget
+    
+    int _usedLines;  // the number of lines that are actually being used, this will be less
+                    // than 'lines' if the character image provided with setImage() is smaller
+                    // than the maximum image size which can be displayed
+
+    int _usedColumns; // the number of columns that are actually being used, this will be less
+                     // than 'columns' if the character image provided with setImage() is smaller
+                     // than the maximum image size which can be displayed
+    
+    int _contentHeight;
+    int _contentWidth;
+    Character* _image; // [lines][columns]
+               // only the area [usedLines][usedColumns] in the image contains valid data
+
+    int _imageSize;
+    QVector<LineProperty> _lineProperties;
+
+    ColorEntry _colorTable[TABLE_COLORS];
+    uint _randomSeed;
+
+    bool _resizing;
+    bool _terminalSizeHint;
+    bool _terminalSizeStartup;
+    bool _bidiEnabled;
+    bool _mouseMarks;
+
+    QPoint  _iPntSel; // initial selection point
+    QPoint  _pntSel; // current selection point
+    QPoint  _tripleSelBegin; // help avoid flicker
+    int     _actSel; // selection state
+    bool    _wordSelectionMode;
+    bool    _lineSelectionMode;
+    bool    _preserveLineBreaks;
+    bool    _columnSelectionMode;
+
+    QClipboard*  _clipboard;
+    QScrollBar* _scrollBar;
+    ScrollBarPosition _scrollbarLocation;
+    QString     _wordCharacters;
+    int         _bellMode;
+
+    bool _blinking;   // hide text in paintEvent
+    bool _hasBlinker; // has characters to blink
+    bool _cursorBlinking;     // hide cursor in paintEvent
+    bool _hasBlinkingCursor;  // has blinking cursor enabled
+    bool _ctrlDrag;           // require Ctrl key for drag
+    TripleClickMode _tripleClickMode;
+    bool _isFixedSize; //Columns / lines are locked.
+    QTimer* _blinkTimer;  // active when hasBlinker
+    QTimer* _blinkCursorTimer;  // active when hasBlinkingCursor
+
+//    KMenu* _drop;
+    QString _dropText;
+    int _dndFileCount;
+
+    bool _possibleTripleClick;  // is set in mouseDoubleClickEvent and deleted
+                               // after QApplication::doubleClickInterval() delay
+
+
+    QLabel* _resizeWidget;
+    QTimer* _resizeTimer;
+
+	bool _flowControlWarningEnabled;
+
+    //widgets related to the warning message that appears when the user presses Ctrl+S to suspend
+    //terminal output - informing them what has happened and how to resume output
+    QLabel* _outputSuspendedLabel; 
+    	
+    uint _lineSpacing;
+
+    bool _colorsInverted; // true during visual bell
+
+    QSize _size;
+	
+    QRgb _blendColor;
+
+    // list of filters currently applied to the display.  used for links and
+    // search highlight
+    TerminalImageFilterChain* _filterChain;
+    QRect _mouseOverHotspotArea;
+
+    KeyboardCursorShape _cursorShape;
+
+    // custom cursor color.  if this is invalid then the foreground
+    // color of the character under the cursor is used
+    QColor _cursorColor;  
+
+
+    struct InputMethodData
+    {
+        QString preeditString;
+        QRect previousPreeditRect;
+    };
+    InputMethodData _inputMethodData;
+
+    static bool _antialiasText;   // do we antialias or not
+
+    //the delay in milliseconds between redrawing blinking text
+    static const int BLINK_DELAY = 500;
+	static const int DEFAULT_LEFT_MARGIN = 1;
+	static const int DEFAULT_TOP_MARGIN = 1;
+
+public:
+    static void setTransparencyEnabled(bool enable)
+    {
+        HAVE_TRANSPARENCY = enable;
+    }
+};
+
+}
+
+#endif // TERMINALDISPLAY_H
new file mode 100644
--- /dev/null
+++ b/gui//Vt102Emulation.cpp
@@ -0,0 +1,1266 @@
+/*
+    This file is part of Konsole, an X terminal.
+    Copyright (C) 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
+
+    Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301  USA.
+*/
+
+// Own
+#include "Vt102Emulation.h"
+
+//#include <config-konsole.h>
+
+
+#if defined(__osf__) || defined(__APPLE__)
+#define AVOID_XKB
+#endif
+
+// this allows konsole to be compiled without XKB and XTEST extensions
+// even though it might be available on a particular system.
+#if defined(AVOID_XKB)
+#undef HAVE_XKB
+#endif
+
+// Standard 
+#include <stdio.h>
+#include <unistd.h>
+#include <assert.h>
+
+// Qt
+#include <QtCore/QEvent>
+#include <QtGui/QKeyEvent>
+#include <QtCore/QByteRef>
+
+// KDE
+//#include <kdebug.h>
+//#include <klocale.h>
+
+// Konsole
+#include "KeyboardTranslator.h"
+#include "Screen.h"
+
+#if defined(HAVE_XKB)
+void scrolllock_set_off();
+void scrolllock_set_on();
+#endif
+
+using namespace Konsole;
+
+/* 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                            */
+/*                                                                           */
+/* ------------------------------------------------------------------------- */
+
+
+Vt102Emulation::Vt102Emulation() 
+    : Emulation(),
+     _titleUpdateTimer(new QTimer(this))
+{
+  _titleUpdateTimer->setSingleShot(true);
+
+  QObject::connect(_titleUpdateTimer , SIGNAL(timeout()) , this , SLOT(updateTitle()));
+
+  initTokenizer();
+  reset();
+}
+
+Vt102Emulation::~Vt102Emulation()
+{
+}
+
+void Vt102Emulation::clearEntireScreen()
+{
+  _currentScreen->clearEntireScreen();
+
+  bufferedUpdate(); 
+}
+
+void Vt102Emulation::reset()
+{
+  //kDebug(1211)<<"Vt102Emulation::reset() resetToken()";
+  resetToken();
+  //kDebug(1211)<<"Vt102Emulation::reset() resetModes()";
+  resetModes();
+  //kDebug(1211)<<"Vt102Emulation::reset() resetCharSet()";
+  resetCharset(0);
+  //kDebug(1211)<<"Vt102Emulation::reset() reset screen0()";
+  _screen[0]->reset();
+  //kDebug(1211)<<"Vt102Emulation::reset() resetCharSet()";
+  resetCharset(1);
+  //kDebug(1211)<<"Vt102Emulation::reset() reset _screen 1";
+  _screen[1]->reset();
+  //kDebug(1211)<<"Vt102Emulation::reset() setCodec()";
+  setCodec(LocaleCodec);
+  //kDebug(1211)<<"Vt102Emulation::reset() done";
+ 
+  bufferedUpdate();
+}
+
+/* ------------------------------------------------------------------------- */
+/*                                                                           */
+/*                     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 separated into `tokens'
+   which are then mapped to a `meaning' provided as operations by the
+   `Screen' class or by the emulation class itself.
+
+   The pipeline proceeds as follows:
+
+   - Tokenizing the ESC codes (onReceiveChar)
+   - 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
+   - CSI_PE     - 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)
+
+#define TY_CSI_PG(A  )  TY_CONSTR(9,A,0)
+
+#define TY_CSI_PE(A  )  TY_CONSTR(10,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 Vt102Emulation::resetToken()
+{
+  ppos = 0; argc = 0; argv[0] = 0; argv[1] = 0;
+}
+
+void Vt102Emulation::addDigit(int dig)
+{
+  argv[argc] = 10*argv[argc] + dig;
+}
+
+void Vt102Emulation::addArgument()
+{
+  argc = qMin(argc+1,MAXARGS-1);
+  argv[argc] = 0;
+}
+
+void Vt102Emulation::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
+#define CPS 64
+
+void Vt102Emulation::initTokenizer()
+{ int i; quint8* 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 = (quint8*)"@ABCDGHILMPSTXZcdfry"; *s; s++) tbl[*s] |= CPN;
+// resize = \e[8;<row>;<col>t
+  for(s = (quint8*)"t"; *s; s++) tbl[*s] |= CPS;
+  for(s = (quint8*)"0123456789"        ; *s; s++) tbl[*s] |= DIG;
+  for(s = (quint8*)"()+*%"             ; *s; s++) tbl[*s] |= SCS;
+  for(s = (quint8*)"()+*#[]%"          ; *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] != '?' && s[2] != '!' && s[2] != '>' && cc < 256 && (tbl[  cc  ] & (C)) == (C))
+#define epp( )     (p >=  3  && s[2] == '?'                              )
+#define epe( )     (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 Vt102Emulation::receiveChar(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 (lec(1,0,ESC+128)) { s[0] = ESC; receiveChar('[');                   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 (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 (eps(    CPN)) { tau( TY_CSI_PN(cc), argv[0],argv[1]);   resetToken(); return; }
+
+// resize = \e[8;<row>;<col>t
+    if (eps(    CPS)) { tau( TY_CSI_PS(cc, argv[0]), argv[1], argv[2]);   resetToken(); return; }
+
+    if (epe(       )) { tau( TY_CSI_PE(cc),     0,  0);       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 if(egt(    ))   { tau( TY_CSI_PG(cc     ),   0,  0); } // spec. case for ESC]>0c or ESC]>c
+    else if (cc == 'm' && argc - i >= 4 && (argv[i] == 38 || argv[i] == 48) && argv[i+1] == 2)
+    { // ESC[ ... 48;2;<red>;<green>;<blue> ... m -or- ESC[ ... 38;2;<red>;<green>;<blue> ... m
+      i += 2;
+      tau( TY_CSI_PS(cc, argv[i-2]), COLOR_SPACE_RGB, (argv[i] << 16) | (argv[i+1] << 8) | argv[i+2]);
+      i += 2;
+    }
+    else if (cc == 'm' && argc - i >= 2 && (argv[i] == 38 || argv[i] == 48) && argv[i+1] == 5)
+    { // ESC[ ... 48;5;<index> ... m -or- ESC[ ... 38;5;<index> ... m
+      i += 2;
+      tau( TY_CSI_PS(cc, argv[i-2]), COLOR_SPACE_256, argv[i]);
+    }
+    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 Vt102Emulation::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
+//  emit changeTitle(arg,unistr);
+  _pendingTitleUpdates[arg] = unistr;
+  _titleUpdateTimer->start(20);
+
+  delete [] str;
+}
+
+void Vt102Emulation::updateTitle()
+{
+	QListIterator<int> iter( _pendingTitleUpdates.keys() );
+	while (iter.hasNext()) {
+		int arg = iter.next();
+		emit titleChanged( arg , _pendingTitleUpdates[arg] );	
+	}
+
+    _pendingTitleUpdates.clear();	
+}
+
+// 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 information
+   about this mapping.
+*/
+
+void Vt102Emulation::tau( int token, int p, int q )
+{
+#if 0
+int N = (token>>0)&0xff;
+int A = (token>>8)&0xff;
+switch( N )
+{
+   case 0: printf("%c", (p < 128) ? p : '?');
+           break;
+   case 1: if (A == 'J') printf("\r");
+           else if (A == 'M') printf("\n");
+           else printf("CTL-%c ", (token>>8)&0xff);
+           break;
+   case 2: printf("ESC-%c ", (token>>8)&0xff);
+           break;
+   case 3: printf("ESC_CS-%c-%c ", (token>>8)&0xff, (token>>16)&0xff);
+           break;
+   case 4: printf("ESC_DE-%c ", (token>>8)&0xff);
+           break;
+   case 5: printf("CSI-PS-%c-%d", (token>>8)&0xff, (token>>16)&0xff );
+           break;
+   case 6: printf("CSI-PN-%c [%d]", (token>>8)&0xff, p);
+           break;
+   case 7: printf("CSI-PR-%c-%d", (token>>8)&0xff, (token>>16)&0xff );
+           break;
+   case 8: printf("VT52-%c", (token>>8)&0xff);
+           break;
+   case 9: printf("CSI-PG-%c", (token>>8)&0xff);
+           break;
+   case 10: printf("CSI-PE-%c", (token>>8)&0xff);
+           break;
+}
+#endif
+
+  switch (token)
+  {
+
+    case TY_CHR(         ) : _currentScreen->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'      ) : emit stateSet(NOTIFYBELL);
+                                break; //VT100
+    case TY_CTL('H'      ) : _currentScreen->BackSpace            (          ); break; //VT100
+    case TY_CTL('I'      ) : _currentScreen->Tabulate             (          ); break; //VT100
+    case TY_CTL('J'      ) : _currentScreen->NewLine              (          ); break; //VT100
+    case TY_CTL('K'      ) : _currentScreen->NewLine              (          ); break; //VT100
+    case TY_CTL('L'      ) : _currentScreen->NewLine              (          ); break; //VT100
+    case TY_CTL('M'      ) : _currentScreen->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'      ) : _currentScreen->ShowCharacter        (    0x2592); break; //VT100
+    case TY_CTL('Y'      ) : /* EM : ignored                      */ break;
+    case TY_CTL('Z'      ) : _currentScreen->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'      ) : _currentScreen->index                (          ); break; //VT100
+    case TY_ESC('E'      ) : _currentScreen->NextLine             (          ); break; //VT100
+    case TY_ESC('H'      ) : _currentScreen->changeTabStop        (true      ); break; //VT100
+    case TY_ESC('M'      ) : _currentScreen->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             (Utf8Codec   ); break; //LINUX
+    case TY_ESC_CS('%', '@') :      setCodec             (LocaleCodec ); break; //LINUX
+
+    case TY_ESC_DE('3'      ) : /* Double height line, top half    */ 
+								_currentScreen->setLineProperty( LINE_DOUBLEWIDTH , true );
+								_currentScreen->setLineProperty( LINE_DOUBLEHEIGHT , true );
+									break;
+    case TY_ESC_DE('4'      ) : /* Double height line, bottom half */ 
+								_currentScreen->setLineProperty( LINE_DOUBLEWIDTH , true );
+								_currentScreen->setLineProperty( LINE_DOUBLEHEIGHT , true );
+									break;
+    case TY_ESC_DE('5'      ) : /* Single width, single height line*/
+								_currentScreen->setLineProperty( LINE_DOUBLEWIDTH , false);
+								_currentScreen->setLineProperty( LINE_DOUBLEHEIGHT , false);
+								break;
+    case TY_ESC_DE('6'      ) : /* Double width, single height line*/ 
+							    _currentScreen->setLineProperty( LINE_DOUBLEWIDTH , true);	
+								_currentScreen->setLineProperty( LINE_DOUBLEHEIGHT , false);
+								break;
+    case TY_ESC_DE('8'      ) : _currentScreen->helpAlign            (          ); break;
+
+// resize = \e[8;<row>;<col>t
+    case TY_CSI_PS('t',   8) : setImageSize( q /* colums */, p /* lines */ );    break;
+
+// change tab text color : \e[28;<color>t  color: 0-16,777,215
+    case TY_CSI_PS('t',   28) : emit changeTabTextColorRequest      ( p        );          break;
+
+    case TY_CSI_PS('K',   0) : _currentScreen->clearToEndOfLine     (          ); break;
+    case TY_CSI_PS('K',   1) : _currentScreen->clearToBeginOfLine   (          ); break;
+    case TY_CSI_PS('K',   2) : _currentScreen->clearEntireLine      (          ); break;
+    case TY_CSI_PS('J',   0) : _currentScreen->clearToEndOfScreen   (          ); break;
+    case TY_CSI_PS('J',   1) : _currentScreen->clearToBeginOfScreen (          ); break;
+    case TY_CSI_PS('J',   2) : _currentScreen->clearEntireScreen    (          ); break;
+    case TY_CSI_PS('g',   0) : _currentScreen->changeTabStop        (false     ); break; //VT100
+    case TY_CSI_PS('g',   3) : _currentScreen->clearTabStops        (          ); break; //VT100
+    case TY_CSI_PS('h',   4) : _currentScreen->    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) : _currentScreen->  resetMode      (MODE_Insert   ); break;
+    case TY_CSI_PS('l',  20) :        resetMode      (MODE_NewLine  ); break;
+    case TY_CSI_PS('s',   0) :      saveCursor           (          ); break;
+    case TY_CSI_PS('u',   0) :      restoreCursor        (          ); break;
+
+    case TY_CSI_PS('m',   0) : _currentScreen->setDefaultRendition  (          ); break;
+    case TY_CSI_PS('m',   1) : _currentScreen->  setRendition     (RE_BOLD     ); break; //VT100
+    case TY_CSI_PS('m',   4) : _currentScreen->  setRendition     (RE_UNDERLINE); break; //VT100
+    case TY_CSI_PS('m',   5) : _currentScreen->  setRendition     (RE_BLINK    ); break; //VT100
+    case TY_CSI_PS('m',   7) : _currentScreen->  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) : _currentScreen->resetRendition     (RE_BOLD     ); break;
+    case TY_CSI_PS('m',  24) : _currentScreen->resetRendition     (RE_UNDERLINE); break;
+    case TY_CSI_PS('m',  25) : _currentScreen->resetRendition     (RE_BLINK    ); break;
+    case TY_CSI_PS('m',  27) : _currentScreen->resetRendition     (RE_REVERSE  ); break;
+
+    case TY_CSI_PS('m',   30) : _currentScreen->setForeColor         (COLOR_SPACE_SYSTEM,  0); break;
+    case TY_CSI_PS('m',   31) : _currentScreen->setForeColor         (COLOR_SPACE_SYSTEM,  1); break;
+    case TY_CSI_PS('m',   32) : _currentScreen->setForeColor         (COLOR_SPACE_SYSTEM,  2); break;
+    case TY_CSI_PS('m',   33) : _currentScreen->setForeColor         (COLOR_SPACE_SYSTEM,  3); break;
+    case TY_CSI_PS('m',   34) : _currentScreen->setForeColor         (COLOR_SPACE_SYSTEM,  4); break;
+    case TY_CSI_PS('m',   35) : _currentScreen->setForeColor         (COLOR_SPACE_SYSTEM,  5); break;
+    case TY_CSI_PS('m',   36) : _currentScreen->setForeColor         (COLOR_SPACE_SYSTEM,  6); break;
+    case TY_CSI_PS('m',   37) : _currentScreen->setForeColor         (COLOR_SPACE_SYSTEM,  7); break;
+
+    case TY_CSI_PS('m',   38) : _currentScreen->setForeColor         (p,       q); break;
+
+    case TY_CSI_PS('m',   39) : _currentScreen->setForeColor         (COLOR_SPACE_DEFAULT,  0); break;
+
+    case TY_CSI_PS('m',   40) : _currentScreen->setBackColor         (COLOR_SPACE_SYSTEM,  0); break;
+    case TY_CSI_PS('m',   41) : _currentScreen->setBackColor         (COLOR_SPACE_SYSTEM,  1); break;
+    case TY_CSI_PS('m',   42) : _currentScreen->setBackColor         (COLOR_SPACE_SYSTEM,  2); break;
+    case TY_CSI_PS('m',   43) : _currentScreen->setBackColor         (COLOR_SPACE_SYSTEM,  3); break;
+    case TY_CSI_PS('m',   44) : _currentScreen->setBackColor         (COLOR_SPACE_SYSTEM,  4); break;
+    case TY_CSI_PS('m',   45) : _currentScreen->setBackColor         (COLOR_SPACE_SYSTEM,  5); break;
+    case TY_CSI_PS('m',   46) : _currentScreen->setBackColor         (COLOR_SPACE_SYSTEM,  6); break;
+    case TY_CSI_PS('m',   47) : _currentScreen->setBackColor         (COLOR_SPACE_SYSTEM,  7); break;
+
+    case TY_CSI_PS('m',   48) : _currentScreen->setBackColor         (p,       q); break;
+
+    case TY_CSI_PS('m',   49) : _currentScreen->setBackColor         (COLOR_SPACE_DEFAULT,  1); break;
+
+    case TY_CSI_PS('m',   90) : _currentScreen->setForeColor         (COLOR_SPACE_SYSTEM,  8); break;
+    case TY_CSI_PS('m',   91) : _currentScreen->setForeColor         (COLOR_SPACE_SYSTEM,  9); break;
+    case TY_CSI_PS('m',   92) : _currentScreen->setForeColor         (COLOR_SPACE_SYSTEM, 10); break;
+    case TY_CSI_PS('m',   93) : _currentScreen->setForeColor         (COLOR_SPACE_SYSTEM, 11); break;
+    case TY_CSI_PS('m',   94) : _currentScreen->setForeColor         (COLOR_SPACE_SYSTEM, 12); break;
+    case TY_CSI_PS('m',   95) : _currentScreen->setForeColor         (COLOR_SPACE_SYSTEM, 13); break;
+    case TY_CSI_PS('m',   96) : _currentScreen->setForeColor         (COLOR_SPACE_SYSTEM, 14); break;
+    case TY_CSI_PS('m',   97) : _currentScreen->setForeColor         (COLOR_SPACE_SYSTEM, 15); break;
+
+    case TY_CSI_PS('m',  100) : _currentScreen->setBackColor         (COLOR_SPACE_SYSTEM,  8); break;
+    case TY_CSI_PS('m',  101) : _currentScreen->setBackColor         (COLOR_SPACE_SYSTEM,  9); break;
+    case TY_CSI_PS('m',  102) : _currentScreen->setBackColor         (COLOR_SPACE_SYSTEM, 10); break;
+    case TY_CSI_PS('m',  103) : _currentScreen->setBackColor         (COLOR_SPACE_SYSTEM, 11); break;
+    case TY_CSI_PS('m',  104) : _currentScreen->setBackColor         (COLOR_SPACE_SYSTEM, 12); break;
+    case TY_CSI_PS('m',  105) : _currentScreen->setBackColor         (COLOR_SPACE_SYSTEM, 13); break;
+    case TY_CSI_PS('m',  106) : _currentScreen->setBackColor         (COLOR_SPACE_SYSTEM, 14); break;
+    case TY_CSI_PS('m',  107) : _currentScreen->setBackColor         (COLOR_SPACE_SYSTEM, 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('@'      ) : _currentScreen->insertChars          (p         ); break;
+    case TY_CSI_PN('A'      ) : _currentScreen->cursorUp             (p         ); break; //VT100
+    case TY_CSI_PN('B'      ) : _currentScreen->cursorDown           (p         ); break; //VT100
+    case TY_CSI_PN('C'      ) : _currentScreen->cursorRight          (p         ); break; //VT100
+    case TY_CSI_PN('D'      ) : _currentScreen->cursorLeft           (p         ); break; //VT100
+    case TY_CSI_PN('G'      ) : _currentScreen->setCursorX           (p         ); break; //LINUX
+    case TY_CSI_PN('H'      ) : _currentScreen->setCursorYX          (p,      q); break; //VT100
+    case TY_CSI_PN('I'      ) : _currentScreen->Tabulate             (p         ); break;
+    case TY_CSI_PN('L'      ) : _currentScreen->insertLines          (p         ); break;
+    case TY_CSI_PN('M'      ) : _currentScreen->deleteLines          (p         ); break;
+    case TY_CSI_PN('P'      ) : _currentScreen->deleteChars          (p         ); break;
+    case TY_CSI_PN('S'      ) : _currentScreen->scrollUp             (p         ); break;
+    case TY_CSI_PN('T'      ) : _currentScreen->scrollDown           (p         ); break;
+    case TY_CSI_PN('X'      ) : _currentScreen->eraseChars           (p         ); break;
+    case TY_CSI_PN('Z'      ) : _currentScreen->backTabulate         (p         ); break;
+    case TY_CSI_PN('c'      ) :      reportTerminalType   (          ); break; //VT100
+    case TY_CSI_PN('d'      ) : _currentScreen->setCursorY           (p         ); break; //LINUX
+    case TY_CSI_PN('f'      ) : _currentScreen->setCursorYX          (p,      q); break; //VT100
+    case TY_CSI_PN('r'      ) :      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) : clearScreenAndSetColumns(132);          break; //VT100
+    case TY_CSI_PR('l',   3) : clearScreenAndSetColumns(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) : _currentScreen->    setMode      (MODE_Screen   ); break; //VT100
+    case TY_CSI_PR('l',   5) : _currentScreen->  resetMode      (MODE_Screen   ); break; //VT100
+
+    case TY_CSI_PR('h',   6) : _currentScreen->    setMode      (MODE_Origin   ); break; //VT100
+    case TY_CSI_PR('l',   6) : _currentScreen->  resetMode      (MODE_Origin   ); break; //VT100
+    case TY_CSI_PR('s',   6) : _currentScreen->   saveMode      (MODE_Origin   ); break; //FIXME
+    case TY_CSI_PR('r',   6) : _currentScreen->restoreMode      (MODE_Origin   ); break; //FIXME
+
+    case TY_CSI_PR('h',   7) : _currentScreen->    setMode      (MODE_Wrap     ); break; //VT100
+    case TY_CSI_PR('l',   7) : _currentScreen->  resetMode      (MODE_Wrap     ); break; //VT100
+    case TY_CSI_PR('s',   7) : _currentScreen->   saveMode      (MODE_Wrap     ); break; //FIXME
+    case TY_CSI_PR('r',   7) : _currentScreen->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('s',   8) : /* IGNORED: autorepeat on            */ break; //VT100
+    case TY_CSI_PR('r',   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('s',   9) : /* IGNORED: interlace                */ break; //VT100
+    case TY_CSI_PR('r',   9) : /* IGNORED: interlace                */ break; //VT100
+
+    case TY_CSI_PR('h',  12) : /* IGNORED: Cursor blink             */ break; //att610
+    case TY_CSI_PR('l',  12) : /* IGNORED: Cursor blink             */ break; //att610
+    case TY_CSI_PR('s',  12) : /* IGNORED: Cursor blink             */ break; //att610
+    case TY_CSI_PR('r',  12) : /* IGNORED: Cursor blink             */ break; //att610
+
+    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('s',  25) :         saveMode      (MODE_Cursor   ); break; //VT100
+    case TY_CSI_PR('r',  25) :      restoreMode      (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('s',  47) :         saveMode      (MODE_AppScreen); break; //XTERM
+    case TY_CSI_PR('r',  47) :      restoreMode      (MODE_AppScreen); break; //XTERM
+
+    case TY_CSI_PR('h',  67) : /* IGNORED: DECBKM                   */ break; //XTERM
+    case TY_CSI_PR('l',  67) : /* IGNORED: DECBKM                   */ break; //XTERM
+    case TY_CSI_PR('s',  67) : /* IGNORED: DECBKM                   */ break; //XTERM
+    case TY_CSI_PR('r',  67) : /* IGNORED: DECBKM                   */ break; //XTERM
+
+    // XTerm defines the following modes:
+    // SET_VT200_MOUSE             1000
+    // SET_VT200_HIGHLIGHT_MOUSE   1001
+    // SET_BTN_EVENT_MOUSE         1002
+    // SET_ANY_EVENT_MOUSE         1003
+    //
+    
+    //Note about mouse modes:
+    //There are four mouse modes which xterm-compatible terminals can support - 1000,1001,1002,1003
+    //Konsole currently supports mode 1000 (basic mouse press and release) and mode 1002 (dragging the mouse).
+    //TODO:  Implementation of mouse modes 1001 (something called hilight tracking) and 
+    //1003 (a slight variation on dragging the mouse)
+    //
+ 
+    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) :        resetMode      (MODE_Mouse1001); 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', 1002) :          setMode      (MODE_Mouse1002); break; //XTERM
+    case TY_CSI_PR('l', 1002) :        resetMode      (MODE_Mouse1002); break; //XTERM
+    case TY_CSI_PR('s', 1002) :         saveMode      (MODE_Mouse1002); break; //XTERM
+    case TY_CSI_PR('r', 1002) :      restoreMode      (MODE_Mouse1002); break; //XTERM
+
+    case TY_CSI_PR('h', 1003) :          setMode      (MODE_Mouse1003); break; //XTERM
+    case TY_CSI_PR('l', 1003) :        resetMode      (MODE_Mouse1003); break; //XTERM
+    case TY_CSI_PR('s', 1003) :         saveMode      (MODE_Mouse1003); break; //XTERM
+    case TY_CSI_PR('r', 1003) :      restoreMode      (MODE_Mouse1003); break; //XTERM
+
+    case TY_CSI_PR('h', 1047) :          setMode      (MODE_AppScreen); break; //XTERM
+    case TY_CSI_PR('l', 1047) : _screen[1]->clearEntireScreen(); resetMode(MODE_AppScreen); break; //XTERM
+    case TY_CSI_PR('s', 1047) :         saveMode      (MODE_AppScreen); break; //XTERM
+    case TY_CSI_PR('r', 1047) :      restoreMode      (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
+    case TY_CSI_PR('s', 1048) :      saveCursor           (          ); break; //XTERM
+    case TY_CSI_PR('r', 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) : saveCursor(); _screen[1]->clearEntireScreen(); setMode(MODE_AppScreen); break; //XTERM
+    case TY_CSI_PR('l', 1049) : resetMode(MODE_AppScreen); restoreCursor(); break; //XTERM
+
+    //FIXME: weird DEC reset sequence
+    case TY_CSI_PE('p'      ) : /* IGNORED: reset         (        ) */ break;
+
+    //FIXME: when changing between vt52 and ansi mode evtl do some resetting.
+    case TY_VT52('A'      ) : _currentScreen->cursorUp             (         1); break; //VT52
+    case TY_VT52('B'      ) : _currentScreen->cursorDown           (         1); break; //VT52
+    case TY_VT52('C'      ) : _currentScreen->cursorRight          (         1); break; //VT52
+    case TY_VT52('D'      ) : _currentScreen->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'      ) : _currentScreen->setCursorYX          (1,1       ); break; //VT52
+    case TY_VT52('I'      ) : _currentScreen->reverseIndex         (          ); break; //VT52
+    case TY_VT52('J'      ) : _currentScreen->clearToEndOfScreen   (          ); break; //VT52
+    case TY_VT52('K'      ) : _currentScreen->clearToEndOfLine     (          ); break; //VT52
+    case TY_VT52('Y'      ) : _currentScreen->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
+
+    case TY_CSI_PG('c'      ) :  reportSecondaryAttributes(          ); break; //VT100
+
+    default : ReportErrorToken();    break;
+  };
+}
+
+void Vt102Emulation::clearScreenAndSetColumns(int columnCount)
+{
+    setImageSize(_currentScreen->getLines(),columnCount); 
+    clearEntireScreen();
+    setDefaultMargins(); 
+    _currentScreen->setCursorYX(0,0);
+}
+
+/* ------------------------------------------------------------------------- */
+/*                                                                           */
+/*                          Terminal to Host protocol                        */
+/*                                                                           */
+/* ------------------------------------------------------------------------- */
+
+/* 
+   Outgoing bytes originate from several sources:
+
+   - Replies to Enquieries.
+   - Mouse Events
+   - Keyboard Events
+*/
+
+/*!
+*/
+
+void Vt102Emulation::sendString(const char* s , int length)
+{
+  if ( length >= 0 )
+    emit sendData(s,length);
+  else
+    emit sendData(s,strlen(s));
+}
+
+// Replies ----------------------------------------------------------------- --
+
+// This section copes with replies send as response to an enquiery control code.
+
+/*!
+*/
+
+void Vt102Emulation::reportCursorPosition()
+{ char tmp[20];
+  sprintf(tmp,"\033[%d;%dR",_currentScreen->getCursorY()+1,_currentScreen->getCursorX()+1);
+  sendString(tmp);
+}
+
+/*
+   What follows here is rather obsolete and faked stuff.
+   The correspondent enquieries are neverthenless issued.
+*/
+
+/*!
+*/
+
+void Vt102Emulation::reportTerminalType()
+{
+  // Primary device attribute response (Request was: ^[[0c or ^[[c (from TT321 Users Guide))
+  //   VT220:  ^[[?63;1;2;3;6;7;8c   (list deps on emul. capabilities)
+  //   VT100:  ^[[?1;2c
+  //   VT101:  ^[[?1;0c
+  //   VT102:  ^[[?6v
+  if (getMode(MODE_Ansi))
+    sendString("\033[?1;2c");     // I'm a VT100
+  else
+    sendString("\033/Z");         // I'm a VT52
+}
+
+void Vt102Emulation::reportSecondaryAttributes()
+{
+  // Seconday device attribute response (Request was: ^[[>0c or ^[[>c)
+  if (getMode(MODE_Ansi))
+    sendString("\033[>0;115;0c"); // Why 115?  ;)
+  else
+    sendString("\033/Z");         // FIXME I don't think VT52 knows about it but kept for
+                                  // konsoles backward compatibility.
+}
+
+void Vt102Emulation::reportTerminalParms(int p)
+// DECREPTPARM
+{ char tmp[100];
+  sprintf(tmp,"\033[%d;1;1;112;112;1;0x",p); // not really true.
+  sendString(tmp);
+}
+
+/*!
+*/
+
+void Vt102Emulation::reportStatus()
+{
+  sendString("\033[0n"); //VT100. Device status report. 0 = Ready.
+}
+
+/*!
+*/
+
+#define ANSWER_BACK "" // This is really obsolete VT100 stuff.
+
+void Vt102Emulation::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).
+
+    eventType represents the kind of mouse action that occurred:
+    	0 = Mouse button press or release
+	1 = Mouse drag
+*/
+
+void Vt102Emulation::sendMouseEvent( int cb, int cx, int cy , int eventType )
+{ char tmp[20];
+  if (  cx<1 || cy<1 ) return;
+  // normal buttons are passed as 0x20 + button,
+  // mouse wheel (buttons 4,5) as 0x5c + button
+  if (cb >= 4) cb += 0x3c;
+
+  //Mouse motion handling
+  if ( (getMode(MODE_Mouse1002) || getMode(MODE_Mouse1003)) && eventType == 1 )
+	  cb += 0x20; //add 32 to signify motion event
+
+  sprintf(tmp,"\033[M%c%c%c",cb+0x20,cx+0x20,cy+0x20);
+  sendString(tmp);
+}
+
+// Keyboard Handling ------------------------------------------------------- --
+
+#define encodeMode(M,B) BITS(B,getMode(M))
+#define encodeStat(M,B) BITS(B,((ev->modifiers() & (M)) == (M)))
+
+void Vt102Emulation::sendText( const QString& text )
+{
+  if (!text.isEmpty()) {
+    QKeyEvent event(QEvent::KeyPress, 
+                    0, 
+                    Qt::NoModifier, 
+                    text);
+    sendKeyEvent(&event); // expose as a big fat keypress event
+  }
+
+}
+
+void Vt102Emulation::sendKeyEvent( QKeyEvent* event )
+{
+    Qt::KeyboardModifiers modifiers = event->modifiers();
+    KeyboardTranslator::States states = KeyboardTranslator::NoState;
+
+    // get current states
+    if ( getMode(MODE_NewLine)  ) states |= KeyboardTranslator::NewLineState;
+    if ( getMode(MODE_Ansi)     ) states |= KeyboardTranslator::AnsiState;
+    if ( getMode(MODE_AppCuKeys)) states |= KeyboardTranslator::CursorKeysState;
+    if ( getMode(MODE_AppScreen)) states |= KeyboardTranslator::AlternateScreenState;
+
+    // lookup key binding
+    if ( _keyTranslator )
+    {
+    KeyboardTranslator::Entry entry = _keyTranslator->findEntry( 
+                                                event->key() , 
+                                                modifiers,
+                                                states );
+
+        // send result to terminal
+        QByteArray textToSend;
+
+        // special handling for the Alt (aka. Meta) modifier.  pressing
+        // Alt+[Character] results in Esc+[Character] being sent
+        // (unless there is an entry defined for this particular combination
+        //  in the keyboard modifier)
+        bool wantsAltModifier = entry.modifiers() & entry.modifierMask() & Qt::AltModifier;
+		bool wantsAnyModifier = entry.state() & entry.stateMask() & KeyboardTranslator::AnyModifierState;
+
+        if ( modifiers & Qt::AltModifier && !(wantsAltModifier || wantsAnyModifier) 
+             && !event->text().isEmpty() )
+        {
+            textToSend.prepend("\033");
+        }
+
+        if ( entry.command() != KeyboardTranslator::NoCommand )
+        {
+			if (entry.command() & KeyboardTranslator::EraseCommand)
+				textToSend += getErase();
+            // TODO command handling
+        }
+        else if ( !entry.text().isEmpty() ) 
+        {
+            textToSend += _codec->fromUnicode(entry.text(true,modifiers));
+        }
+        else
+            textToSend += _codec->fromUnicode(event->text());
+
+        sendData( textToSend.constData() , textToSend.length() );
+    }
+    else
+    {
+        // print an error message to the terminal if no key translator has been
+        // set
+        QString translatorError =  ("No keyboard translator available.  "
+                                         "The information needed to convert key presses "
+                                         "into characters to send to the terminal " 
+                                         "is missing.");
+
+        reset();
+        receiveData( translatorError.toAscii().constData() , translatorError.count() );
+    }
+}
+
+/* ------------------------------------------------------------------------- */
+/*                                                                           */
+/*                                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 TerminalDisplay.C, since 
+   it might involve VT100 enhanced fonts, which have these
+   particular glyphs allocated in (0x00-0x1f) in their code page.
+*/
+
+#define CHARSET _charset[_currentScreen==_screen[1]]
+
+// Apply current character map.
+
+unsigned short Vt102Emulation::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 Vt102Emulation::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 Vt102Emulation::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 Vt102Emulation::setAndUseCharset(int n, int cs)
+{
+  CHARSET.charset[n&3] = cs;
+  useCharset(n&3);
+}
+
+void Vt102Emulation::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
+}
+
+void Vt102Emulation::setDefaultMargins()
+{
+	_screen[0]->setDefaultMargins();
+	_screen[1]->setDefaultMargins();
+}
+
+void Vt102Emulation::setMargins(int t, int b)
+{
+  _screen[0]->setMargins(t, b);
+  _screen[1]->setMargins(t, b);
+}
+
+/*! Save the cursor position and the rendition attribute settings. */
+
+void Vt102Emulation::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;
+  _currentScreen->saveCursor();
+}
+
+/*! Restore the cursor position and the rendition attribute settings. */
+
+void Vt102Emulation::restoreCursor()
+{
+  CHARSET.graphic = CHARSET.sa_graphic;
+  CHARSET.pound   = CHARSET.sa_pound; //This mode is obsolete
+  _currentScreen->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 Vt102Emulation::resetModes()
+{
+  resetMode(MODE_Mouse1000); saveMode(MODE_Mouse1000);
+  resetMode(MODE_Mouse1001); saveMode(MODE_Mouse1001);
+  resetMode(MODE_Mouse1002); saveMode(MODE_Mouse1002);
+  resetMode(MODE_Mouse1003); saveMode(MODE_Mouse1003);
+
+  resetMode(MODE_AppScreen); saveMode(MODE_AppScreen);
+  // here come obsolete modes
+  resetMode(MODE_AppCuKeys); saveMode(MODE_AppCuKeys);
+  resetMode(MODE_NewLine  );
+    setMode(MODE_Ansi     );
+}
+
+void Vt102Emulation::setMode(int m)
+{
+  _currParm.mode[m] = true;
+  switch (m)
+  {
+    case MODE_Mouse1000:
+    case MODE_Mouse1001:
+    case MODE_Mouse1002:
+    case MODE_Mouse1003:
+ 	    emit programUsesMouseChanged(false); 
+    break;
+
+    case MODE_AppScreen : _screen[1]->clearSelection();
+                          setScreen(1);
+    break;
+  }
+  if (m < MODES_SCREEN || m == MODE_NewLine)
+  {
+    _screen[0]->setMode(m);
+    _screen[1]->setMode(m);
+  }
+}
+
+void Vt102Emulation::resetMode(int m)
+{
+  _currParm.mode[m] = false;
+  switch (m)
+  {
+    case MODE_Mouse1000 : 
+    case MODE_Mouse1001 :
+    case MODE_Mouse1002 :
+    case MODE_Mouse1003 :
+	    emit programUsesMouseChanged(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 Vt102Emulation::saveMode(int m)
+{
+  _saveParm.mode[m] = _currParm.mode[m];
+}
+
+void Vt102Emulation::restoreMode(int m)
+{
+  if (_saveParm.mode[m]) 
+      setMode(m); 
+  else 
+      resetMode(m);
+}
+
+bool Vt102Emulation::getMode(int m)
+{
+  return _currParm.mode[m];
+}
+
+char Vt102Emulation::getErase() const
+{
+  KeyboardTranslator::Entry entry = _keyTranslator->findEntry(
+                                            Qt::Key_Backspace,
+                                            0,
+                                            0);
+  if ( entry.text().count() > 0 )
+      return entry.text()[0];
+  else
+      return '\b';
+}
+
+/* ------------------------------------------------------------------------- */
+/*                                                                           */
+/*                               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 Vt102Emulation::scan_buffer_report()
+{
+  if (ppos == 0 || ppos == 1 && (pbuf[0] & 0xff) >= 32) return;
+  printf("token: "); hexdump(pbuf,ppos); printf("\n");
+}
+
+/*!
+*/
+
+void Vt102Emulation::ReportErrorToken()
+{
+#ifndef NDEBUG
+  printf("undecodable "); scan_buffer_report();
+#endif
+}
+
+//#include "moc_Vt102Emulation.cpp"
+
new file mode 100644
--- /dev/null
+++ b/gui//Vt102Emulation.h
@@ -0,0 +1,192 @@
+/*
+    This file is part of Konsole, an X terminal.
+    
+    Copyright (C) 2007 by Robert Knight <robertknight@gmail.com>
+    Copyright (C) 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
+
+    Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301  USA.
+*/
+
+#ifndef VT102EMULATION_H
+#define VT102EMULATION_H
+
+// Standard Library
+#include <stdio.h>
+
+// Qt 
+#include <QtGui/QKeyEvent>
+#include <QtCore/QHash>
+#include <QtCore/QTimer>
+
+// Konsole
+#include "Emulation.h"
+#include "Screen.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_Mouse1001 (MODES_SCREEN+4)
+#define MODE_Mouse1002 (MODES_SCREEN+5)
+#define MODE_Mouse1003 (MODES_SCREEN+6)
+#define MODE_Ansi      (MODES_SCREEN+7)
+#define MODE_total     (MODES_SCREEN+8)
+
+namespace Konsole
+{
+
+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
+};
+
+/**
+ * Provides an xterm compatible terminal emulation based on the DEC VT102 terminal.
+ * A full description of this terminal can be found at http://vt100.net/docs/vt102-ug/
+ * 
+ * In addition, various additional xterm escape sequences are supported to provide 
+ * features such as mouse input handling.
+ * See http://rtfm.etla.org/xterm/ctlseq.html for a description of xterm's escape
+ * sequences. 
+ *
+ */
+class Vt102Emulation : public Emulation
+{ 
+Q_OBJECT
+
+public:
+
+  /** Constructs a new emulation */
+  Vt102Emulation();
+  ~Vt102Emulation();
+  
+  // reimplemented
+  virtual void clearEntireScreen();
+  virtual void reset();
+  
+  // reimplemented
+  virtual char getErase() const;
+  
+public slots: 
+
+  // reimplemented 
+  virtual void sendString(const char*,int length = -1);
+  virtual void sendText(const QString& text);
+  virtual void sendKeyEvent(QKeyEvent*);
+  virtual void sendMouseEvent( int buttons, int column, int line , int eventType );
+  
+protected:
+  // reimplemented
+  virtual void setMode    (int mode);
+  virtual void resetMode  (int mode);
+
+  // reimplemented 
+  virtual void receiveChar(int cc);
+  
+
+private slots:
+		
+  //causes changeTitle() to be emitted for each (int,QString) pair in pendingTitleUpdates
+  //used to buffer multiple title updates
+  void updateTitle();
+
+
+private:
+  unsigned short applyCharset(unsigned short c);
+  void setCharset(int n, int cs);
+  void useCharset(int n);
+  void setAndUseCharset(int n, int cs);
+  void saveCursor();
+  void restoreCursor();
+  void resetCharset(int scrno);
+
+  void setMargins(int top, int bottom);
+  //set margins for all screens back to their defaults
+  void setDefaultMargins();
+
+  // returns true if 'mode' is set or false otherwise
+  bool getMode    (int mode);
+  // saves the current boolean value of 'mode'
+  void saveMode   (int mode);
+  // restores the boolean value of 'mode' 
+  void restoreMode(int mode);
+  // resets all modes
+  void resetModes();
+
+  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 reportSecondaryAttributes();
+  void reportStatus();
+  void reportAnswerBack();
+  void reportCursorPosition();
+  void reportTerminalParms(int p);
+
+  void onScrollLock();
+  void scrollLock(const bool lock);
+
+  // clears the screen and resizes it to the specified
+  // number of columns
+  void clearScreenAndSetColumns(int columnCount);
+
+  CharCodes _charset[2];
+
+  DECpar _currParm;
+  DECpar _saveParm;
+
+  //hash table and timer for buffering calls to the session instance 
+  //to update the name of the session
+  //or window title.
+  //these calls occur when certain escape sequences are seen in the 
+  //output from the terminal
+  QHash<int,QString> _pendingTitleUpdates;
+  QTimer* _titleUpdateTimer;
+  
+};
+
+}
+
+#endif // VT102EMULATION_H
new file mode 100644
--- /dev/null
+++ b/gui//default.keytab
@@ -0,0 +1,128 @@
+# [README.default.Keytab] Buildin Keyboard Table
+#
+# To customize your keyboard, copy this file to something
+# ending with .keytab and change it to meet you needs.
+# Please read the README.KeyTab and the README.keyboard
+# in this case.
+#
+# --------------------------------------------------------------
+
+keyboard "Default (XFree 4)"
+
+# --------------------------------------------------------------
+#
+# Note that this particular table is a "risc" version made to
+# ease customization without bothering with obsolete details.
+# See VT100.keytab for the more hairy stuff.
+#
+# --------------------------------------------------------------
+
+# common keys
+
+key Escape             : "\E"
+
+key Tab   -Shift       : "\t"
+key Tab   +Shift+Ansi  : "\E[Z"
+key Tab   +Shift-Ansi  : "\t"
+key Backtab     +Ansi  : "\E[Z"
+key Backtab     -Ansi  : "\t"
+
+key Return-Shift-NewLine : "\r"
+key Return-Shift+NewLine : "\r\n"
+
+key Return+Shift         : "\EOM"
+
+# Backspace and Delete codes are preserving CTRL-H.
+
+key Backspace      : "\x7f"
+
+# Arrow keys in VT52 mode
+# shift up/down are reserved for scrolling.
+# shift left/right are reserved for switching between tabs (this is hardcoded).
+
+key Up   -Shift-Ansi : "\EA"
+key Down -Shift-Ansi : "\EB"
+key Right-Shift-Ansi : "\EC"
+key Left -Shift-Ansi : "\ED"
+
+# Arrow keys in ANSI mode with Application - and Normal Cursor Mode)
+
+key Up    -Shift-AnyMod+Ansi+AppCuKeys           : "\EOA"
+key Down  -Shift-AnyMod+Ansi+AppCuKeys           : "\EOB"
+key Right -Shift-AnyMod+Ansi+AppCuKeys           : "\EOC"
+key Left  -Shift-AnyMod+Ansi+AppCuKeys           : "\EOD"
+
+key Up    -Shift-AnyMod+Ansi-AppCuKeys           : "\E[A"
+key Down  -Shift-AnyMod+Ansi-AppCuKeys           : "\E[B"
+key Right -Shift-AnyMod+Ansi-AppCuKeys           : "\E[C"
+key Left  -Shift-AnyMod+Ansi-AppCuKeys           : "\E[D"
+
+key Up    -Shift+AnyMod+Ansi                     : "\E[1;*A"
+key Down  -Shift+AnyMod+Ansi                     : "\E[1;*B"
+key Right -Shift+AnyMod+Ansi                     : "\E[1;*C"
+key Left  -Shift+AnyMod+Ansi                     : "\E[1;*D"
+
+# other grey PC keys
+
+key Enter+NewLine : "\r\n"
+key Enter-NewLine : "\r"
+
+key Home        -AnyMod     -AppCuKeys           : "\E[H"  
+key End         -AnyMod     -AppCuKeys           : "\E[F"  
+key Home        -AnyMod     +AppCuKeys           : "\EOH"  
+key End         -AnyMod     +AppCuKeys           : "\EOF"  
+key Home        +AnyMod                          : "\E[1;*H"
+key End         +AnyMod                          : "\E[1;*F"
+
+key Insert      -AnyMod                          : "\E[2~"
+key Delete      -AnyMod                          : "\E[3~"
+key Insert      +AnyMod                          : "\E[2;*~"
+key Delete      +AnyMod                          : "\E[3;*~"
+
+key Prior -Shift-AnyMod                          : "\E[5~"
+key Next  -Shift-AnyMod                          : "\E[6~"
+key Prior -Shift+AnyMod                          : "\E[5;*~"
+key Next  -Shift+AnyMod                          : "\E[6;*~"
+
+# Function keys
+key F1          -AnyMod                          : "\EOP"
+key F2          -AnyMod                          : "\EOQ"
+key F3          -AnyMod                          : "\EOR"
+key F4          -AnyMod                          : "\EOS"
+key F5          -AnyMod                          : "\E[15~"
+key F6          -AnyMod                          : "\E[17~"
+key F7          -AnyMod                          : "\E[18~"
+key F8          -AnyMod                          : "\E[19~"
+key F9          -AnyMod                          : "\E[20~"
+key F10         -AnyMod                          : "\E[21~"
+key F11         -AnyMod                          : "\E[23~"
+key F12         -AnyMod                          : "\E[24~"
+
+key F1          +AnyMod                          : "\EO*P"
+key F2          +AnyMod                          : "\EO*Q"
+key F3          +AnyMod                          : "\EO*R"
+key F4          +AnyMod                          : "\EO*S"
+key F5          +AnyMod                          : "\E[15;*~"
+key F6          +AnyMod                          : "\E[17;*~"
+key F7          +AnyMod                          : "\E[18;*~"
+key F8          +AnyMod                          : "\E[19;*~"
+key F9          +AnyMod                          : "\E[20;*~"
+key F10         +AnyMod                          : "\E[21;*~"
+key F11         +AnyMod                          : "\E[23;*~"
+key F12         +AnyMod                          : "\E[24;*~"
+
+# Work around dead keys
+
+key Space +Control : "\x00"
+
+# Some keys are used by konsole to cause operations.
+# The scroll* operations refer to the history buffer.
+
+key Up    +Shift-AppScreen  : scrollLineUp
+key Prior +Shift-AppScreen  : scrollPageUp
+key Down  +Shift-AppScreen  : scrollLineDown
+key Next  +Shift-AppScreen  : scrollPageDown
+
+key ScrollLock     : scrollLock
+
+# keypad characters are not offered differently by Qt.
new file mode 100644
--- /dev/null
+++ b/gui//k3process.cpp
@@ -0,0 +1,1053 @@
+/*
+   This file is part of the KDE libraries
+   Copyright (C) 1997 Christian Czezatke (e9025461@student.tuwien.ac.at)
+
+    Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public
+   License as published by the Free Software Foundation; either
+   version 2 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public License
+   along with this library; see the file COPYING.LIB.  If not, write to
+   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.
+*/
+
+
+#include "k3process.h"
+//#include <config.h>
+
+#include "k3processcontroller.h"
+#include "kpty.h"
+
+#ifdef __osf__
+#define _OSF_SOURCE
+#include <float.h>
+#endif
+
+#ifdef _AIX
+#define _ALL_SOURCE
+#endif
+
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+
+#include <errno.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <time.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <grp.h>
+
+#include <QtCore/QMap>
+#include <QtCore/QFile>
+#include <QtCore/QSocketNotifier>
+
+//#include <kdebug.h>
+//#include <kstandarddirs.h>
+//#include <kuser.h>
+
+
+//////////////////
+// private data //
+//////////////////
+
+class K3ProcessPrivate {
+public:
+   K3ProcessPrivate() :
+     usePty(K3Process::NoCommunication),
+     addUtmp(false), useShell(false),
+     pty(0),
+     priority(0)
+   {
+   }
+
+   K3Process::Communication usePty;
+   bool addUtmp : 1;
+   bool useShell : 1;
+
+   KPty *pty;
+
+   int priority;
+
+   QMap<QString,QString> env;
+   QString wd;
+   QByteArray shell;
+   QByteArray executable;
+};
+
+/////////////////////////////
+// public member functions //
+/////////////////////////////
+
+K3Process::K3Process( QObject* parent )
+  : QObject( parent ),
+    run_mode(NotifyOnExit),
+    runs(false),
+    pid_(0),
+    status(0),
+    keepPrivs(false),
+    innot(0),
+    outnot(0),
+    errnot(0),
+    communication(NoCommunication),
+    input_data(0),
+    input_sent(0),
+    input_total(0),
+	 d(new K3ProcessPrivate)
+{
+  K3ProcessController::ref();
+  K3ProcessController::instance()->addKProcess(this);
+
+
+  out[0] = out[1] = -1;
+  in[0] = in[1] = -1;
+  err[0] = err[1] = -1;
+}
+
+void
+K3Process::setEnvironment(const QString &name, const QString &value)
+{
+   d->env.insert(name, value);
+}
+
+void
+K3Process::setWorkingDirectory(const QString &dir)
+{
+   d->wd = dir;
+}
+
+void
+K3Process::setupEnvironment()
+{
+   QMap<QString,QString>::Iterator it;
+   for(it = d->env.begin(); it != d->env.end(); ++it)
+   {
+      setenv(QFile::encodeName(it.key()).data(),
+             QFile::encodeName(it.value()).data(), 1);
+   }
+   if (!d->wd.isEmpty())
+   {
+      chdir(QFile::encodeName(d->wd).data());
+   }
+}
+
+void
+K3Process::setRunPrivileged(bool keepPrivileges)
+{
+   keepPrivs = keepPrivileges;
+}
+
+bool
+K3Process::runPrivileged() const
+{
+   return keepPrivs;
+}
+
+bool
+K3Process::setPriority(int prio)
+{
+    if (runs) {
+        if (setpriority(PRIO_PROCESS, pid_, prio))
+            return false;
+    } else {
+        if (prio > 19 || prio < (geteuid() ? getpriority(PRIO_PROCESS, 0) : -20))
+            return false;
+    }
+    d->priority = prio;
+    return true;
+}
+
+K3Process::~K3Process()
+{
+  if (run_mode != DontCare)
+    kill(SIGKILL);
+  detach();
+
+  delete d->pty;
+  delete d;
+
+  K3ProcessController::instance()->removeKProcess(this);
+  K3ProcessController::deref();
+}
+
+void K3Process::detach()
+{
+  if (runs) {
+    K3ProcessController::instance()->addProcess(pid_);
+    runs = false;
+    pid_ = 0; // close without draining
+    commClose(); // Clean up open fd's and socket notifiers.
+  }
+}
+
+void K3Process::setBinaryExecutable(const char *filename)
+{
+   d->executable = filename;
+}
+
+K3Process &K3Process::operator<<(const QStringList& args)
+{
+  QStringList::ConstIterator it = args.begin();
+  for ( ; it != args.end() ; ++it )
+      arguments.append(QFile::encodeName(*it));
+  return *this;
+}
+
+K3Process &K3Process::operator<<(const QByteArray& arg)
+{
+  return operator<< (arg.data());
+}
+
+K3Process &K3Process::operator<<(const char* arg)
+{
+  arguments.append(arg);
+  return *this;
+}
+
+K3Process &K3Process::operator<<(const QString& arg)
+{
+  arguments.append(QFile::encodeName(arg));
+  return *this;
+}
+
+void K3Process::clearArguments()
+{
+  arguments.clear();
+}
+
+bool K3Process::start(RunMode runmode, Communication comm)
+{
+  if (runs) {
+    qDebug() << "Attempted to start an already running process" << endl;
+    return false;
+  }
+
+  uint n = arguments.count();
+  if (n == 0) {
+    qDebug() << "Attempted to start a process without arguments" << endl;
+    return false;
+  }
+  char **arglist;
+  QByteArray shellCmd;
+  if (d->useShell)
+  {
+      if (d->shell.isEmpty()) {
+        qDebug() << "Invalid shell specified" << endl;
+        return false;
+      }
+
+      for (uint i = 0; i < n; i++) {
+          shellCmd += arguments[i];
+          shellCmd += ' '; // CC: to separate the arguments
+      }
+
+      arglist = static_cast<char **>(malloc( 4 * sizeof(char *)));
+      arglist[0] = d->shell.data();
+      arglist[1] = (char *) "-c";
+      arglist[2] = shellCmd.data();
+      arglist[3] = 0;
+  }
+  else
+  {
+      arglist = static_cast<char **>(malloc( (n + 1) * sizeof(char *)));
+      for (uint i = 0; i < n; i++)
+         arglist[i] = arguments[i].data();
+      arglist[n] = 0;
+  }
+
+  run_mode = runmode;
+
+  if (!setupCommunication(comm))
+  {
+      qDebug() << "Could not setup Communication!" << endl;
+      free(arglist);
+      return false;
+  }
+
+  // We do this in the parent because if we do it in the child process
+  // gdb gets confused when the application runs from gdb.
+#ifdef HAVE_INITGROUPS
+  struct passwd *pw = geteuid() ? 0 : getpwuid(getuid());
+#endif
+
+  int fd[2];
+  if (pipe(fd))
+     fd[0] = fd[1] = -1; // Pipe failed.. continue
+
+  // we don't use vfork() because
+  // - it has unclear semantics and is not standardized
+  // - we do way too much magic in the child
+  pid_ = fork();
+  if (pid_ == 0) {
+        // The child process
+
+        close(fd[0]);
+        // Closing of fd[1] indicates that the execvp() succeeded!
+        fcntl(fd[1], F_SETFD, FD_CLOEXEC);
+
+        if (!commSetupDoneC())
+          qDebug() << "Could not finish comm setup in child!" << endl;
+
+        // reset all signal handlers
+        struct sigaction act;
+        sigemptyset(&act.sa_mask);
+        act.sa_handler = SIG_DFL;
+        act.sa_flags = 0;
+        for (int sig = 1; sig < NSIG; sig++)
+          sigaction(sig, &act, 0L);
+
+        if (d->priority)
+            setpriority(PRIO_PROCESS, 0, d->priority);
+
+        if (!runPrivileged())
+        {
+           setgid(getgid());
+#ifdef HAVE_INITGROUPS
+           if (pw)
+              initgroups(pw->pw_name, pw->pw_gid);
+#endif
+	   if (geteuid() != getuid())
+	       setuid(getuid());
+	   if (geteuid() != getuid())
+	       _exit(1);
+        }
+
+        setupEnvironment();
+
+        if (runmode == DontCare || runmode == OwnGroup)
+          setsid();
+
+        const char *executable = arglist[0];
+        if (!d->executable.isEmpty())
+           executable = d->executable.data();
+        execvp(executable, arglist);
+
+        char resultByte = 1;
+        write(fd[1], &resultByte, 1);
+        _exit(-1);
+  } else if (pid_ == -1) {
+        // forking failed
+
+        // commAbort();
+        pid_ = 0;
+        free(arglist);
+        return false;
+  }
+  // the parent continues here
+  free(arglist);
+
+  if (!commSetupDoneP())
+    qDebug() << "Could not finish comm setup in parent!" << endl;
+
+  // Check whether client could be started.
+  close(fd[1]);
+  for(;;)
+  {
+     char resultByte;
+     int n = ::read(fd[0], &resultByte, 1);
+     if (n == 1)
+     {
+         // exec() failed
+         close(fd[0]);
+         waitpid(pid_, 0, 0);
+         pid_ = 0;
+         commClose();
+         return false;
+     }
+     if (n == -1)
+     {
+        if (errno == EINTR)
+           continue; // Ignore
+     }
+     break; // success
+  }
+  close(fd[0]);
+
+  runs = true;
+  switch (runmode)
+  {
+  case Block:
+    for (;;)
+    {
+      commClose(); // drain only, unless obsolete reimplementation
+      if (!runs)
+      {
+        // commClose detected data on the process exit notifification pipe
+        K3ProcessController::instance()->unscheduleCheck();
+        if (waitpid(pid_, &status, WNOHANG) != 0) // error finishes, too
+        {
+          commClose(); // this time for real (runs is false)
+          K3ProcessController::instance()->rescheduleCheck();
+          break;
+        }
+        runs = true; // for next commClose() iteration
+      }
+      else
+      {
+        // commClose is an obsolete reimplementation and waited until
+        // all output channels were closed (or it was interrupted).
+        // there is a chance that it never gets here ...
+        waitpid(pid_, &status, 0);
+        runs = false;
+        break;
+      }
+    }
+    // why do we do this? i think this signal should be emitted _only_
+    // after the process has successfully run _asynchronously_ --ossi
+    emit processExited(this);
+    break;
+  default: // NotifyOnExit & OwnGroup
+    input_data = 0; // Discard any data for stdin that might still be there
+    break;
+  }
+  return true;
+}
+
+
+
+bool K3Process::kill(int signo)
+{
+  if (runs && pid_ > 0 && !::kill(run_mode == OwnGroup ? -pid_ : pid_, signo))
+    return true;
+  return false;
+}
+
+
+
+bool K3Process::isRunning() const
+{
+  return runs;
+}
+
+
+
+pid_t K3Process::pid() const
+{
+  return pid_;
+}
+
+#ifndef timersub
+# define timersub(a, b, result) \
+  do { \
+    (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
+    (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
+    if ((result)->tv_usec < 0) { \
+      --(result)->tv_sec; \
+      (result)->tv_usec += 1000000; \
+    } \
+  } while (0)
+#endif
+
+bool K3Process::wait(int timeout)
+{
+  if (!runs)
+    return true;
+
+#ifndef __linux__
+  struct timeval etv;
+#endif
+  struct timeval tv, *tvp;
+  if (timeout < 0)
+    tvp = 0;
+  else
+  {
+#ifndef __linux__
+    gettimeofday(&etv, 0);
+    etv.tv_sec += timeout;
+#else
+    tv.tv_sec = timeout;
+    tv.tv_usec = 0;
+#endif
+    tvp = &tv;
+  }
+
+  int fd = K3ProcessController::instance()->notifierFd();
+  for(;;)
+  {
+    fd_set fds;
+    FD_ZERO( &fds );
+    FD_SET( fd, &fds );
+
+#ifndef __linux__
+    if (tvp)
+    {
+      gettimeofday(&tv, 0);
+      timersub(&etv, &tv, &tv);
+      if (tv.tv_sec < 0)
+        tv.tv_sec = tv.tv_usec = 0;
+    }
+#endif
+
+    switch( select( fd+1, &fds, 0, 0, tvp ) )
+    {
+    case -1:
+      if( errno == EINTR )
+        break;
+      // fall through; should happen if tvp->tv_sec < 0
+    case 0:
+      K3ProcessController::instance()->rescheduleCheck();
+      return false;
+    default:
+      K3ProcessController::instance()->unscheduleCheck();
+      if (waitpid(pid_, &status, WNOHANG) != 0) // error finishes, too
+      {
+        processHasExited(status);
+        K3ProcessController::instance()->rescheduleCheck();
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+
+
+bool K3Process::normalExit() const
+{
+  return (pid_ != 0) && !runs && WIFEXITED(status);
+}
+
+
+bool K3Process::signalled() const
+{
+  return (pid_ != 0) && !runs && WIFSIGNALED(status);
+}
+
+
+bool K3Process::coreDumped() const
+{
+#ifdef WCOREDUMP
+  return signalled() && WCOREDUMP(status);
+#else
+  return false;
+#endif
+}
+
+
+int K3Process::exitStatus() const
+{
+  return WEXITSTATUS(status);
+}
+
+
+int K3Process::exitSignal() const
+{
+  return WTERMSIG(status);
+}
+
+
+bool K3Process::writeStdin(const char *buffer, int buflen)
+{
+  // if there is still data pending, writing new data
+  // to stdout is not allowed (since it could also confuse
+  // kprocess ...)
+  if (input_data != 0)
+    return false;
+
+  if (communication & Stdin) {
+    input_data = buffer;
+    input_sent = 0;
+    input_total = buflen;
+    innot->setEnabled(true);
+    if (input_total)
+       slotSendData(0);
+    return true;
+  } else
+    return false;
+}
+
+void K3Process::suspend()
+{
+  if (outnot)
+     outnot->setEnabled(false);
+}
+
+void K3Process::resume()
+{
+  if (outnot)
+     outnot->setEnabled(true);
+}
+
+bool K3Process::closeStdin()
+{
+  if (communication & Stdin) {
+    communication = communication & ~Stdin;
+    delete innot;
+    innot = 0;
+    if (!(d->usePty & Stdin))
+      close(in[1]);
+    in[1] = -1;
+    return true;
+  } else
+    return false;
+}
+
+bool K3Process::closeStdout()
+{
+  if (communication & Stdout) {
+    communication = communication & ~Stdout;
+    delete outnot;
+    outnot = 0;
+    if (!(d->usePty & Stdout))
+      close(out[0]);
+    out[0] = -1;
+    return true;
+  } else
+    return false;
+}
+
+bool K3Process::closeStderr()
+{
+  if (communication & Stderr) {
+    communication = communication & ~Stderr;
+    delete errnot;
+    errnot = 0;
+    if (!(d->usePty & Stderr))
+      close(err[0]);
+    err[0] = -1;
+    return true;
+  } else
+    return false;
+}
+
+bool K3Process::closePty()
+{
+  if (d->pty && d->pty->masterFd() >= 0) {
+    if (d->addUtmp)
+      d->pty->logout();
+    d->pty->close();
+    return true;
+  } else
+    return false;
+}
+
+void K3Process::closeAll()
+{
+  closeStdin();
+  closeStdout();
+  closeStderr();
+  closePty();
+}
+
+/////////////////////////////
+// protected slots         //
+/////////////////////////////
+
+
+
+void K3Process::slotChildOutput(int fdno)
+{
+  if (!childOutput(fdno))
+     closeStdout();
+}
+
+
+void K3Process::slotChildError(int fdno)
+{
+  if (!childError(fdno))
+     closeStderr();
+}
+
+
+void K3Process::slotSendData(int)
+{
+  if (input_sent == input_total) {
+    innot->setEnabled(false);
+    input_data = 0;
+    emit wroteStdin(this);
+  } else {
+    int result = ::write(in[1], input_data+input_sent, input_total-input_sent);
+    if (result >= 0)
+    {
+       input_sent += result;
+    }
+    else if ((errno != EAGAIN) && (errno != EINTR))
+    {
+       qDebug() << "Error writing to stdin of child process" << endl;
+       closeStdin();
+    }
+  }
+}
+
+void K3Process::setUseShell(bool useShell, const char *shell)
+{
+  d->useShell = useShell;
+  if (shell && *shell)
+    d->shell = shell;
+  else
+// #ifdef NON_FREE // ... as they ship non-POSIX /bin/sh
+#if !defined(__linux__) && !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__) && !defined(__GNU__) && !defined(__DragonFly__)
+  // Solaris POSIX ...
+  if (!access( "/usr/xpg4/bin/sh", X_OK ))
+    d->shell = "/usr/xpg4/bin/sh";
+  else
+  // ... which links here anyway
+  if (!access( "/bin/ksh", X_OK ))
+    d->shell = "/bin/ksh";
+  else
+  // dunno, maybe superfluous?
+  if (!access( "/usr/ucb/sh", X_OK ))
+    d->shell = "/usr/ucb/sh";
+  else
+#endif
+    d->shell = "/bin/sh";
+}
+
+void K3Process::setUsePty(Communication usePty, bool addUtmp)
+{
+  d->usePty = usePty;
+  d->addUtmp = addUtmp;
+  if (usePty) {
+    if (!d->pty)
+      d->pty = new KPty;
+  } else {
+    delete d->pty;
+    d->pty = 0;
+  }
+}
+
+KPty *K3Process::pty() const
+{
+  return d->pty;
+}
+
+QString K3Process::quote(const QString &arg)
+{
+    QChar q('\'');
+    return QString(arg).replace(q, "'\\''").prepend(q).append(q);
+}
+
+
+//////////////////////////////
+// private member functions //
+//////////////////////////////
+
+
+void K3Process::processHasExited(int state)
+{
+    // only successfully run NotifyOnExit processes ever get here
+
+    status = state;
+    runs = false; // do this before commClose, so it knows we're dead
+
+    commClose(); // cleanup communication sockets
+
+    if (run_mode != DontCare)
+      emit processExited(this);
+}
+
+
+
+int K3Process::childOutput(int fdno)
+{
+  if (communication & NoRead) {
+     int len = -1;
+     emit receivedStdout(fdno, len);
+     errno = 0; // Make sure errno doesn't read "EAGAIN"
+     return len;
+  }
+  else
+  {
+     char buffer[1025];
+     int len;
+
+     len = ::read(fdno, buffer, 1024);
+
+     if (len > 0) {
+        buffer[len] = 0; // Just in case.
+        emit receivedStdout(this, buffer, len);
+     }
+     return len;
+  }
+}
+
+int K3Process::childError(int fdno)
+{
+  char buffer[1025];
+  int len;
+
+  len = ::read(fdno, buffer, 1024);
+
+  if (len > 0) {
+     buffer[len] = 0; // Just in case.
+     emit receivedStderr(this, buffer, len);
+  }
+  return len;
+}
+
+
+int K3Process::setupCommunication(Communication comm)
+{
+  // PTY stuff //
+  if (d->usePty)
+  {
+    // cannot communicate on both stderr and stdout if they are both on the pty
+    if (!(~(comm & d->usePty) & (Stdout | Stderr))) {
+       qWarning() << "Invalid usePty/communication combination (" << d->usePty << "/" << comm << ")" << endl;
+       return 0;
+    }
+    if (!d->pty->open())
+       return 0;
+
+    int rcomm = comm & d->usePty;
+    int mfd = d->pty->masterFd();
+    if (rcomm & Stdin)
+      in[1] = mfd;
+    if (rcomm & Stdout)
+      out[0] = mfd;
+    if (rcomm & Stderr)
+      err[0] = mfd;
+  }
+
+  communication = comm;
+
+  comm = comm & ~d->usePty;
+  if (comm & Stdin) {
+    if (socketpair(AF_UNIX, SOCK_STREAM, 0, in))
+      goto fail0;
+    fcntl(in[0], F_SETFD, FD_CLOEXEC);
+    fcntl(in[1], F_SETFD, FD_CLOEXEC);
+  }
+  if (comm & Stdout) {
+    if (socketpair(AF_UNIX, SOCK_STREAM, 0, out))
+      goto fail1;
+    fcntl(out[0], F_SETFD, FD_CLOEXEC);
+    fcntl(out[1], F_SETFD, FD_CLOEXEC);
+  }
+  if (comm & Stderr) {
+    if (socketpair(AF_UNIX, SOCK_STREAM, 0, err))
+      goto fail2;
+    fcntl(err[0], F_SETFD, FD_CLOEXEC);
+    fcntl(err[1], F_SETFD, FD_CLOEXEC);
+  }
+  return 1; // Ok
+ fail2:
+  if (comm & Stdout)
+  {
+    close(out[0]);
+    close(out[1]);
+    out[0] = out[1] = -1;
+  }
+ fail1:
+  if (comm & Stdin)
+  {
+    close(in[0]);
+    close(in[1]);
+    in[0] = in[1] = -1;
+  }
+ fail0:
+  communication = NoCommunication;
+  return 0; // Error
+}
+
+
+
+int K3Process::commSetupDoneP()
+{
+  int rcomm = communication & ~d->usePty;
+  if (rcomm & Stdin)
+    close(in[0]);
+  if (rcomm & Stdout)
+    close(out[1]);
+  if (rcomm & Stderr)
+    close(err[1]);
+  in[0] = out[1] = err[1] = -1;
+
+  // Don't create socket notifiers if no interactive comm is to be expected
+  if (run_mode != NotifyOnExit && run_mode != OwnGroup)
+    return 1;
+
+  if (communication & Stdin) {
+    fcntl(in[1], F_SETFL, O_NONBLOCK | fcntl(in[1], F_GETFL));
+    innot =  new QSocketNotifier(in[1], QSocketNotifier::Write, this);
+    Q_CHECK_PTR(innot);
+    innot->setEnabled(false); // will be enabled when data has to be sent
+    QObject::connect(innot, SIGNAL(activated(int)),
+                     this, SLOT(slotSendData(int)));
+  }
+
+  if (communication & Stdout) {
+    outnot = new QSocketNotifier(out[0], QSocketNotifier::Read, this);
+    Q_CHECK_PTR(outnot);
+    QObject::connect(outnot, SIGNAL(activated(int)),
+                     this, SLOT(slotChildOutput(int)));
+    if (communication & NoRead)
+        suspend();
+  }
+
+  if (communication & Stderr) {
+    errnot = new QSocketNotifier(err[0], QSocketNotifier::Read, this );
+    Q_CHECK_PTR(errnot);
+    QObject::connect(errnot, SIGNAL(activated(int)),
+                     this, SLOT(slotChildError(int)));
+  }
+
+  return 1;
+}
+
+
+
+int K3Process::commSetupDoneC()
+{
+  int ok = 1;
+  if (d->usePty & Stdin) {
+    if (dup2(d->pty->slaveFd(), STDIN_FILENO) < 0) ok = 0;
+  } else if (communication & Stdin) {
+    if (dup2(in[0], STDIN_FILENO) < 0) ok = 0;
+  } else {
+    int null_fd = open( "/dev/null", O_RDONLY );
+    if (dup2( null_fd, STDIN_FILENO ) < 0) ok = 0;
+    close( null_fd );
+  }
+  struct linger so;
+  memset(&so, 0, sizeof(so));
+  if (d->usePty & Stdout) {
+    if (dup2(d->pty->slaveFd(), STDOUT_FILENO) < 0) ok = 0;
+  } else if (communication & Stdout) {
+    if (dup2(out[1], STDOUT_FILENO) < 0 ||
+        setsockopt(out[1], SOL_SOCKET, SO_LINGER, (char *)&so, sizeof(so)))
+      ok = 0;
+    if (communication & MergedStderr) {
+      if (dup2(out[1], STDERR_FILENO) < 0)
+        ok = 0;
+    }
+  }
+  if (d->usePty & Stderr) {
+    if (dup2(d->pty->slaveFd(), STDERR_FILENO) < 0) ok = 0;
+  } else if (communication & Stderr) {
+    if (dup2(err[1], STDERR_FILENO) < 0 ||
+        setsockopt(err[1], SOL_SOCKET, SO_LINGER, (char *)&so, sizeof(so)))
+      ok = 0;
+  }
+
+  // don't even think about closing all open fds here or anywhere else
+
+  // PTY stuff //
+  if (d->usePty) {
+    d->pty->setCTty();
+    if (d->addUtmp)
+      d->pty->login(getenv("USER"), getenv("DISPLAY"));
+  }
+
+  return ok;
+}
+
+
+
+void K3Process::commClose()
+{
+  closeStdin();
+
+  if (pid_) { // detached, failed, and killed processes have no output. basta. :)
+    // If both channels are being read we need to make sure that one socket
+    // buffer doesn't fill up whilst we are waiting for data on the other
+    // (causing a deadlock). Hence we need to use select.
+
+    int notfd = K3ProcessController::instance()->notifierFd();
+
+    while ((communication & (Stdout | Stderr)) || runs) {
+      fd_set rfds;
+      FD_ZERO(&rfds);
+      struct timeval timeout, *p_timeout;
+
+      int max_fd = 0;
+      if (communication & Stdout) {
+        FD_SET(out[0], &rfds);
+        max_fd = out[0];
+      }
+      if (communication & Stderr) {
+        FD_SET(err[0], &rfds);
+        if (err[0] > max_fd)
+          max_fd = err[0];
+      }
+      if (runs) {
+        FD_SET(notfd, &rfds);
+        if (notfd > max_fd)
+          max_fd = notfd;
+        // If the process is still running we block until we
+        // receive data or the process exits.
+        p_timeout = 0; // no timeout
+      } else {
+        // If the process has already exited, we only check
+        // the available data, we don't wait for more.
+        timeout.tv_sec = timeout.tv_usec = 0; // timeout immediately
+        p_timeout = &timeout;
+      }
+
+      int fds_ready = select(max_fd+1, &rfds, 0, 0, p_timeout);
+      if (fds_ready < 0) {
+        if (errno == EINTR)
+          continue;
+        break;
+      } else if (!fds_ready)
+        break;
+
+      if ((communication & Stdout) && FD_ISSET(out[0], &rfds))
+        slotChildOutput(out[0]);
+
+      if ((communication & Stderr) && FD_ISSET(err[0], &rfds))
+        slotChildError(err[0]);
+
+      if (runs && FD_ISSET(notfd, &rfds)) {
+        runs = false; // hack: signal potential exit
+        return; // don't close anything, we will be called again
+      }
+    }
+  }
+
+  closeStdout();
+  closeStderr();
+
+  closePty();
+}
+
+
+
+///////////////////////////
+// CC: Class K3ShellProcess
+///////////////////////////
+
+K3ShellProcess::K3ShellProcess(const char *shellname):
+  K3Process(), d(0)
+{
+  setUseShell( true, shellname ? shellname : getenv("SHELL") );
+}
+
+K3ShellProcess::~K3ShellProcess() {
+}
+
+QString K3ShellProcess::quote(const QString &arg)
+{
+    return K3Process::quote(arg);
+}
+
+bool K3ShellProcess::start(RunMode runmode, Communication comm)
+{
+  return K3Process::start(runmode, comm);
+}
+
+
+//#include "moc_k3process.cpp"
new file mode 100644
--- /dev/null
+++ b/gui//k3process.h
@@ -0,0 +1,890 @@
+/* This file is part of the KDE libraries
+    Copyright (C) 1997 Christian Czezakte (e9025461@student.tuwien.ac.at)
+
+    Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public License
+    along with this library; see the file COPYING.LIB.  If not, write to
+    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+    Boston, MA 02110-1301, USA.
+*/
+
+#ifndef K3PROCESS_H
+#define K3PROCESS_H
+
+#include <QtCore/QObject>
+
+#include <sys/types.h> // for pid_t
+#include <sys/wait.h>
+#include <signal.h>
+#include <unistd.h>
+
+class QSocketNotifier;
+class K3ProcessPrivate;
+class KPty;
+
+/**
+ * @obsolete Use KProcess and KPtyProcess instead.
+ *
+ * Child process invocation, monitoring and control.
+ * This class works only in the application's main thread.
+ *
+ * <b>General usage and features:</b>\n
+ *
+ * This class allows a KDE application to start child processes without having
+ * to worry about UN*X signal handling issues and zombie process reaping.
+ *
+ * @see K3ProcIO
+ *
+ * Basically, this class distinguishes three different ways of running
+ * child processes:
+ *
+ * @li  DontCare -- The child process is invoked and both the child
+ * process and the parent process continue concurrently.
+ *
+ * The process is started in an own session (see setsid(2)).
+ *
+ * @li  NotifyOnExit -- The child process is invoked and both the
+ * child and the parent process run concurrently.
+ *
+ * When the child process exits, the K3Process instance
+ * corresponding to it emits the Qt signal processExited().
+ * Since this signal is @em not emitted from within a UN*X
+ * signal handler, arbitrary function calls can be made.
+ *
+ * Be aware: When the K3Process object gets destructed, the child
+ * process will be killed if it is still running!
+ * This means in particular, that it usually makes no sense to use
+ * a K3Process on the stack with NotifyOnExit.
+ *
+ * @li  OwnGroup -- like NotifyOnExit, but the child process is started
+ * in an own process group (and an own session, FWIW). The behavior of
+ * kill() changes to killing the whole process group - this makes
+ * this mode useful for implementing primitive job management. It can be
+ * used to work around broken wrapper scripts that don't propagate signals
+ * to the "real" program. However, use this with care, as you disturb the
+ * shell's job management if your program is started from the command line.
+ *
+ * @li  Block -- The child process starts and the parent process
+ * is suspended until the child process exits. (@em Really not recommended
+ * for programs with a GUI.)
+ * In this mode the parent can read the child's output, but can't send it any
+ * input.
+ *
+ * K3Process also provides several functions for determining the exit status
+ * and the pid of the child process it represents.
+ *
+ * Furthermore it is possible to supply command-line arguments to the process
+ * in a clean fashion (no null-terminated stringlists and such...)
+ *
+ * A small usage example:
+ * \code
+ *   K3Process *proc = new K3Process;
+ *
+ *   *proc << "my_executable";
+ *   *proc << "These" << "are" << "the" << "command" << "line" << "args";
+ *   QApplication::connect(proc, SIGNAL(processExited(K3Process *)),
+ *                         pointer_to_my_object, SLOT(my_objects_slot(K3Process *)));
+ *   proc->start();
+ * \endcode
+ *
+ * This will start "my_executable" with the commandline arguments "These"...
+ *
+ * When the child process exits, the slot will be invoked.
+ *
+ * <b>Communication with the child process:</b>\n
+ *
+ * K3Process supports communication with the child process through
+ * stdin/stdout/stderr.
+ *
+ * The following functions are provided for getting data from the child
+ * process or sending data to the child's stdin (For more information,
+ * have a look at the documentation of each function):
+ *
+ * @li writeStdin()
+ *  -- Transmit data to the child process' stdin. When all data was sent, the
+ * signal wroteStdin() is emitted.
+ *
+ * @li When data arrives at stdout or stderr, the signal receivedStdout()
+ * resp. receivedStderr() is emitted.
+ *
+ * @li You can shut down individual communication channels with
+ * closeStdin(), closeStdout(), and closeStderr(), resp.
+ *
+ * @author Christian Czezatke e9025461@student.tuwien.ac.at
+ *
+ **/
+class K3Process : public QObject
+{
+  Q_OBJECT
+
+public:
+
+  /**
+   * Modes in which the communication channels can be opened.
+   *
+   * If communication for more than one channel is required,
+   * the values should be or'ed together, for example to get
+   * communication with stdout as well as with stdin, you would
+   * specify @p Stdin | @p Stdout
+   *
+   */
+  enum CommunicationFlag {
+       NoCommunication = 0, /**< No communication with the process. */
+       Stdin = 1, /**< Connect to write to the process with writeStdin(). */
+       Stdout = 2, /**< Connect to read from the process' output. */
+       Stderr = 4, /**< Connect to read from the process' stderr. */
+       AllOutput = 6, /**< Connects to all output channels. */
+       All = 7, /**< Connects to all channels. */
+       NoRead = 8, /**< If specified with Stdout, no data is actually read from stdout,
+                    * only the signal receivedStdout(int fd, int &len) is emitted. */
+       CTtyOnly = NoRead, /**< Tells setUsePty() to create a PTY for the process
+                           * and make it the process' controlling TTY, but does not
+                           * redirect any I/O channel to the PTY. */
+       MergedStderr = 16  /**< If specified with Stdout, the process' stderr will be
+                           * redirected onto the same file handle as its stdout, i.e.,
+                           * all error output will be signalled with receivedStdout().
+                           * Don't specify Stderr if you specify MergedStderr. */
+  };
+
+  Q_DECLARE_FLAGS(Communication, CommunicationFlag)
+
+  /**
+   * Run-modes for a child process.
+   */
+  enum RunMode {
+      /**
+       * The application does not receive notifications from the subprocess when
+       * it is finished or aborted.
+       */
+       DontCare,
+       /**
+        * The application is notified when the subprocess dies.
+        */
+       NotifyOnExit,
+       /**
+        * The application is suspended until the started process is finished.
+        */
+       Block,
+       /**
+        * Same as NotifyOnExit, but the process is run in an own session,
+        * just like with DontCare.
+        */
+       OwnGroup
+  };
+
+  /**
+   * Constructor
+   */
+  explicit K3Process( QObject* parent=0L );
+
+  /**
+   *Destructor:
+   *
+   *  If the process is running when the destructor for this class
+   *  is called, the child process is killed with a SIGKILL, but
+   *  only if the run mode is not of type @p DontCare.
+   *  Processes started as @p DontCare keep running anyway.
+  */
+  virtual ~K3Process();
+
+  /**
+   * Sets the executable and the command line argument list for this process.
+   *
+   * For example, doing an "ls -l /usr/local/bin" can be achieved by:
+   *  \code
+   *  K3Process p;
+   *  ...
+   *  p << "ls" << "-l" << "/usr/local/bin"
+   *  \endcode
+   *
+   * @param arg the argument to add
+   * @return a reference to this K3Process
+   **/
+  K3Process &operator<<(const QString& arg);
+  /**
+   * Similar to previous method, takes a char *, supposed to be in locale 8 bit already.
+   */
+  K3Process &operator<<(const char * arg);
+  /**
+   * Similar to previous method, takes a QByteArray, supposed to be in locale 8 bit already.
+   * @param arg the argument to add
+   * @return a reference to this K3Process
+   */
+  K3Process &operator<<(const QByteArray & arg);
+
+  /**
+   * Sets the executable and the command line argument list for this process,
+   * in a single method call, or add a list of arguments.
+   * @param args the arguments to add
+   * @return a reference to this K3Process
+   **/
+  K3Process &operator<<(const QStringList& args);
+
+  /**
+   * Clear a command line argument list that has been set by using
+   * operator<<.
+  */
+  void clearArguments();
+
+  /**
+   *  Starts the process.
+   *  For a detailed description of the
+   *  various run modes and communication semantics, have a look at the
+   *  general description of the K3Process class. Note that if you use
+   * setUsePty( Stdout | Stderr, \<bool\> ), you cannot use Stdout | Stderr
+   *  here - instead, use Stdout only to receive the mixed output.
+   *
+   *  The following problems could cause this function to
+   *    return false:
+   *
+   *  @li The process is already running.
+   *  @li The command line argument list is empty.
+   *  @li The the @p comm parameter is incompatible with the selected pty usage.
+   *  @li The starting of the process failed (could not fork).
+   *  @li The executable was not found.
+   *
+   *  @param runmode The Run-mode for the process.
+   *  @param comm  Specifies which communication channels should be
+   *  established to the child process (stdin/stdout/stderr). By default,
+   *  no communication takes place and the respective communication
+   *  signals will never get emitted.
+   *
+   *  @return true on success, false on error
+   *  (see above for error conditions)
+   **/
+  virtual bool start(RunMode  runmode = NotifyOnExit,
+                     Communication comm = NoCommunication);
+
+  /**
+   * Stop the process (by sending it a signal).
+   *
+   * @param signo The signal to send. The default is SIGTERM.
+   * @return true if the signal was delivered successfully.
+  */
+  virtual bool kill(int signo = SIGTERM);
+
+  /**
+   * Checks whether the process is running.
+   * @return true if the process is (still) considered to be running
+  */
+  bool isRunning() const;
+
+  /** Returns the process id of the process.
+   *
+   * If it is called after
+   * the process has exited, it returns the process id of the last
+   *  child process that was created by this instance of K3Process.
+   *
+   *  Calling it before any child process has been started by this
+   *  K3Process instance causes pid() to return 0.
+   * @return the pid of the process or 0 if no process has been started yet.
+   **/
+  pid_t pid() const;
+
+  /**
+   * Suspend processing of data from stdout of the child process.
+   */
+  void suspend();
+
+  /**
+   * Resume processing of data from stdout of the child process.
+   */
+  void resume();
+
+  /**
+   * Suspend execution of the current thread until the child process dies
+   * or the timeout hits. This function is not recommended for programs
+   * with a GUI.
+   * @param timeout timeout in seconds. -1 means wait indefinitely.
+   * @return true if the process exited, false if the timeout hit.
+   */
+  bool wait(int timeout = -1);
+
+  /**
+   * Checks whether the process exited cleanly.
+   *
+   * @return true if the process has already finished and has exited
+   *  "voluntarily", ie: it has not been killed by a signal.
+   */
+  bool normalExit() const;
+
+  /**
+   * Checks whether the process was killed by a signal.
+   *
+   * @return true if the process has already finished and has not exited
+   * "voluntarily", ie: it has been killed by a signal.
+   */
+  bool signalled() const;
+
+  /**
+   * Checks whether a killed process dumped core.
+   *
+   * @return true if signalled() returns true and the process
+   * dumped core. Note that on systems that don't define the
+   * WCOREDUMP macro, the return value is always false.
+   */
+  bool coreDumped() const;
+
+  /**
+   * Returns the exit status of the process.
+   *
+   * @return the exit status of the process. Note that this value
+   * is not valid if normalExit() returns false.
+   */
+  int exitStatus() const;
+
+  /**
+   * Returns the signal the process was killed by.
+   *
+   * @return the signal number that caused the process to exit.
+   * Note that this value is not valid if signalled() returns false.
+   */
+  int exitSignal() const;
+
+  /**
+   *	 Transmit data to the child process' stdin.
+   *
+   * This function may return false in the following cases:
+   *
+   *     @li The process is not currently running.
+   * This implies that you cannot use this function in Block mode.
+   *
+   *     @li Communication to stdin has not been requested in the start() call.
+   *
+   *     @li Transmission of data to the child process by a previous call to
+   * writeStdin() is still in progress.
+   *
+   * Please note that the data is sent to the client asynchronously,
+   * so when this function returns, the data might not have been
+   * processed by the child process.
+   * That means that you must not free @p buffer or call writeStdin()
+   * again until either a wroteStdin() signal indicates that the
+   * data has been sent or a processExited() signal shows that
+   * the child process is no longer alive.
+   *
+   * If all the data has been sent to the client, the signal
+   * wroteStdin() will be emitted.
+   *
+   * This function does not work when the process is start()ed in Block mode.
+   *
+   * @param buffer the buffer to write
+   * @param buflen the length of the buffer
+   * @return false if an error has occurred
+   **/
+  bool writeStdin(const char *buffer, int buflen);
+
+  /**
+   * Shuts down the Stdin communication link. If no pty is used, this
+   * causes "EOF" to be indicated on the child's stdin file descriptor.
+   *
+   * @return false if no Stdin communication link exists (any more).
+   */
+  bool closeStdin();
+
+  /**
+   * Shuts down the Stdout communication link. If no pty is used, any further
+   * attempts by the child to write to its stdout file descriptor will cause
+   * it to receive a SIGPIPE.
+   *
+   * @return false if no Stdout communication link exists (any more).
+   */
+  bool closeStdout();
+
+  /**
+   * Shuts down the Stderr communication link. If no pty is used, any further
+   * attempts by the child to write to its stderr file descriptor will cause
+   * it to receive a SIGPIPE.
+   *
+   * @return false if no Stderr communication link exists (any more).
+   */
+  bool closeStderr();
+
+  /**
+   * Deletes the optional utmp entry and closes the pty.
+   *
+   * Make sure to shut down any communication links that are using the pty
+   * before calling this function.
+   *
+   * @return false if the pty is not open (any more).
+   */
+  bool closePty();
+
+  /**
+   * @brief Close stdin, stdout, stderr and the pty
+   *
+   * This is the same that calling all close* functions in a row:
+   * @see closeStdin, @see closeStdout, @see closeStderr and @see closePty
+   */
+  void closeAll();
+
+  /**
+   * Lets you see what your arguments are for debugging.
+   * @return the list of arguments
+   */
+  const QList<QByteArray> &args() /* const */ { return arguments; }
+
+  /**
+   * Controls whether the started process should drop any
+   * setuid/setgid privileges or whether it should keep them.
+   * Note that this function is mostly a dummy, as the KDE libraries
+   * currently refuse to run with setuid/setgid privileges.
+   *
+   * The default is false: drop privileges
+   * @param keepPrivileges true to keep the privileges
+   */
+  void setRunPrivileged(bool keepPrivileges);
+
+  /**
+   * Returns whether the started process will drop any
+   * setuid/setgid privileges or whether it will keep them.
+   * @return true if the process runs privileged
+   */
+  bool runPrivileged() const;
+
+  /**
+   * Adds the variable @p name to the process' environment.
+   * This function must be called before starting the process.
+   * @param name the name of the environment variable
+   * @param value the new value for the environment variable
+   */
+  void setEnvironment(const QString &name, const QString &value);
+
+  /**
+   * Changes the current working directory (CWD) of the process
+   * to be started.
+   * This function must be called before starting the process.
+   * @param dir the new directory
+   */
+  void setWorkingDirectory(const QString &dir);
+
+  /**
+   * Specify whether to start the command via a shell or directly.
+   * The default is to start the command directly.
+   * If @p useShell is true @p shell will be used as shell, or
+   * if shell is empty, /bin/sh will be used.
+   *
+   * When using a shell, the caller should make sure that all filenames etc.
+   * are properly quoted when passed as argument.
+   * @see quote()
+   * @param useShell true if the command should be started via a shell
+   * @param shell the path to the shell that will execute the process, or
+   *              0 to use /bin/sh. Use getenv("SHELL") to use the user's
+   *              default shell, but note that doing so is usually a bad idea
+   *              for shell compatibility reasons.
+   */
+  void setUseShell(bool useShell, const char *shell = 0);
+
+  /**
+   * This function can be used to quote an argument string such that
+   * the shell processes it properly. This is e. g. necessary for
+   * user-provided file names which may contain spaces or quotes.
+   * It also prevents expansion of wild cards and environment variables.
+   * @param arg the argument to quote
+   * @return the quoted argument
+   */
+  static QString quote(const QString &arg);
+
+  /**
+   * Detaches K3Process from child process. All communication is closed.
+   * No exit notification is emitted any more for the child process.
+   * Deleting the K3Process will no longer kill the child process.
+   * Note that the current process remains the parent process of the
+   * child process.
+   */
+  void detach();
+
+  /**
+   * Specify whether to create a pty (pseudo-terminal) for running the
+   * command.
+   * This function should be called before starting the process.
+   *
+   * @param comm for which stdio handles to use a pty. Note that it is not
+   *  allowed to specify Stdout and Stderr at the same time both here and to
+   * start (there is only one pty, so they cannot be distinguished).
+   * @param addUtmp true if a utmp entry should be created for the pty
+   */
+  void setUsePty(Communication comm, bool addUtmp);
+
+  /**
+   * Obtains the pty object used by this process. The return value is
+   * valid only after setUsePty() was used with a non-zero argument.
+   * The pty is open only while the process is running.
+   * @return a pointer to the pty object
+   */
+  KPty *pty() const;
+
+  /**
+   * More or less intuitive constants for use with setPriority().
+   */
+  enum { PrioLowest = 20, PrioLow = 10, PrioLower = 5, PrioNormal = 0,
+    PrioHigher = -5, PrioHigh = -10, PrioHighest = -19 };
+
+  /**
+   * Sets the scheduling priority of the process.
+   * @param prio the new priority in the range -20 (high) to 19 (low).
+   * @return false on error; see setpriority(2) for possible reasons.
+   */
+  bool setPriority(int prio);
+
+Q_SIGNALS:
+  /**
+   * Emitted after the process has terminated when
+   * the process was run in the @p NotifyOnExit  (==default option to
+   * start() ) or the Block mode.
+   * @param proc a pointer to the process that has exited
+   **/
+  void processExited(K3Process *proc);
+
+
+  /**
+   * Emitted, when output from the child process has
+   * been received on stdout.
+   *
+   * To actually get this signal, the Stdout communication link
+   * has to be turned on in start().
+   *
+   * @param proc a pointer to the process that has received the output
+   * @param buffer The data received.
+   * @param buflen The number of bytes that are available.
+   *
+   * You should copy the information contained in @p buffer to your private
+   * data structures before returning from the slot.
+   * Example:
+   * \code
+   *     QString myBuf = QLatin1String(buffer, buflen);
+   * \endcode
+   **/
+  void receivedStdout(K3Process *proc, char *buffer, int buflen);
+
+  /**
+   * Emitted when output from the child process has
+   * been received on stdout.
+   *
+   * To actually get this signal, the Stdout communication link
+   * has to be turned on in start() and the
+   * NoRead flag must have been passed.
+   *
+   * You will need to explicitly call resume() after your call to start()
+   * to begin processing data from the child process' stdout.  This is
+   * to ensure that this signal is not emitted when no one is connected
+   * to it, otherwise this signal will not be emitted.
+   *
+   * The data still has to be read from file descriptor @p fd.
+   * @param fd the file descriptor that provides the data
+   * @param len the number of bytes that have been read from @p fd must
+   *  be written here
+   **/
+  void receivedStdout(int fd, int &len); // KDE4: change, broken API
+
+
+  /**
+   * Emitted, when output from the child process has
+   * been received on stderr.
+   *
+   * To actually get this signal, the Stderr communication link
+   * has to be turned on in start().
+   *
+   * You should copy the information contained in @p buffer to your private
+   * data structures before returning from the slot.
+   *
+   * @param proc a pointer to the process that has received the data
+   * @param buffer The data received.
+   * @param buflen The number of bytes that are available.
+   **/
+  void receivedStderr(K3Process *proc, char *buffer, int buflen);
+
+  /**
+   * Emitted after all the data that has been
+   * specified by a prior call to writeStdin() has actually been
+   * written to the child process.
+   * @param proc a pointer to the process
+   **/
+  void wroteStdin(K3Process *proc);
+
+
+protected Q_SLOTS:
+
+ /**
+  * This slot gets activated when data from the child's stdout arrives.
+  * It usually calls childOutput().
+  * @param fdno the file descriptor for the output
+  */
+  void slotChildOutput(int fdno);
+
+ /**
+  * This slot gets activated when data from the child's stderr arrives.
+  * It usually calls childError().
+  * @param fdno the file descriptor for the output
+  */
+  void slotChildError(int fdno);
+
+  /**
+   * Called when another bulk of data can be sent to the child's
+   * stdin. If there is no more data to be sent to stdin currently
+   * available, this function must disable the QSocketNotifier innot.
+   * @param dummy ignore this argument
+   */
+  void slotSendData(int dummy);	// KDE 4: remove dummy
+
+protected:
+
+  /**
+   * Sets up the environment according to the data passed via
+   * setEnvironment()
+   */
+  void setupEnvironment();
+
+  /**
+   * The list of the process' command line arguments. The first entry
+   * in this list is the executable itself.
+   */
+  QList<QByteArray> arguments;
+  /**
+   * How to run the process (Block, NotifyOnExit, DontCare). You should
+   *  not modify this data member directly from derived classes.
+   */
+  RunMode run_mode;
+  /**
+   * true if the process is currently running. You should not
+   * modify this data member directly from derived classes. Please use
+   * isRunning() for reading the value of this data member since it
+   * will probably be made private in later versions of K3Process.
+   */
+  bool runs;
+
+  /**
+   * The PID of the currently running process.
+   * You should not modify this data member in derived classes.
+   * Please use pid() instead of directly accessing this
+   * member since it will probably be made private in
+   * later versions of K3Process.
+   */
+  pid_t pid_;
+
+  /**
+   * The process' exit status as returned by waitpid(). You should not
+   * modify the value of this data member from derived classes. You should
+   * rather use exitStatus() than accessing this data member directly
+   * since it will probably be made private in further versions of
+   * K3Process.
+   */
+  int status;
+
+
+  /**
+   * If false, the child process' effective uid & gid will be reset to the
+   * real values.
+   * @see setRunPrivileged()
+   */
+  bool keepPrivs;
+
+  /**
+   * This function is called from start() right before a fork() takes
+   * place. According to the @p comm parameter this function has to initialize
+   * the in, out and err data members of K3Process.
+   *
+   * This function should return 1 if setting the needed communication channels
+   * was successful.
+   *
+   * The default implementation is to create UNIX STREAM sockets for the
+   * communication, but you could reimplement this function to establish a
+   * TCP/IP communication for network communication, for example.
+   */
+  virtual int setupCommunication(Communication comm);
+
+  /**
+   * Called right after a (successful) fork() on the parent side. This function
+   * will usually do some communications cleanup, like closing in[0],
+   * out[1] and out[1].
+   *
+   * Furthermore, it must also create the QSocketNotifiers innot,
+   * outnot and errnot and connect their Qt signals to the respective
+   * K3Process slots.
+   *
+   * For a more detailed explanation, it is best to have a look at the default
+   * implementation in kprocess.cpp.
+   */
+  virtual int commSetupDoneP();
+
+  /**
+   * Called right after a (successful) fork(), but before an exec() on the child
+   * process' side. It usually duplicates the in[0], out[1] and
+   * err[1] file handles to the respective standard I/O handles.
+   */
+  virtual int commSetupDoneC();
+
+
+  /**
+   * Immediately called after a successfully started process in NotifyOnExit
+   * mode has exited. This function normally calls commClose()
+   * and emits the processExited() signal.
+   * @param state the exit code of the process as returned by waitpid()
+   */
+  virtual void processHasExited(int state);
+
+  /**
+   * Cleans up the communication links to the child after it has exited.
+   * This function should act upon the values of pid() and runs.
+   * See the kprocess.cpp source for details.
+   * @li If pid() returns zero, the communication links should be closed
+   *  only.
+   * @li if pid() returns non-zero and runs is false, all data
+   *  immediately available from the communication links should be processed
+   *  before closing them.
+   * @li if pid() returns non-zero and runs is true, the communication
+   *  links should be monitored for data until the file handle returned by
+   *  K3ProcessController::theKProcessController->notifierFd() becomes ready
+   *  for reading - when it triggers, runs should be reset to false, and
+   *  the function should be immediately left without closing anything.
+   *
+   * The previous semantics of this function are forward-compatible, but should
+   * be avoided, as they are prone to race conditions and can cause K3Process
+   * (and thus the whole program) to lock up under certain circumstances. At the
+   * end the function closes the communication links in any case. Additionally
+   * @li if runs is true, the communication links are monitored for data
+   *  until all of them have returned EOF. Note that if any system function is
+   *  interrupted (errno == EINTR) the polling loop should be aborted.
+   * @li if runs is false, all data immediately available from the
+   *  communication links is processed.
+   */
+  virtual void commClose();
+
+  /* KDE 4 - commClose will be changed to perform cleanup only in all cases *
+   * If @p notfd is -1, all data immediately available from the
+   *  communication links should be processed.
+   * If @p notfd is not -1, the communication links should be monitored
+   *  for data until the file handle @p notfd becomes ready for reading.
+   */
+//  virtual void commDrain(int notfd);
+
+  /**
+   * Specify the actual executable that should be started (first argument to execve)
+   * Normally the the first argument is the executable but you can
+   * override that with this function.
+   */
+  void setBinaryExecutable(const char *filename);
+
+  /**
+   * The socket descriptors for stdout.
+   */
+  int out[2];
+  /**
+   * The socket descriptors for stdin.
+   */
+  int in[2];
+  /**
+   * The socket descriptors for stderr.
+   */
+  int err[2];
+
+  /**
+   * The socket notifier for in[1].
+   */
+  QSocketNotifier *innot;
+  /**
+   * The socket notifier for out[0].
+   */
+  QSocketNotifier *outnot;
+  /**
+   * The socket notifier for err[0].
+   */
+  QSocketNotifier *errnot;
+
+  /**
+   * Lists the communication links that are activated for the child
+   * process.  Should not be modified from derived classes.
+   */
+  Communication communication;
+
+  /**
+   * Called by slotChildOutput() this function copies data arriving from
+   * the child process' stdout to the respective buffer and emits the signal
+   * receivedStdout().
+   */
+  int childOutput(int fdno);
+
+  /**
+   * Called by slotChildError() this function copies data arriving from
+   * the child process' stderr to the respective buffer and emits the signal
+   * receivedStderr().
+   */
+  int childError(int fdno);
+
+  /**
+   * The buffer holding the data that has to be sent to the child
+   */
+  const char *input_data;
+  /**
+   * The number of bytes already transmitted
+   */
+  int input_sent;
+  /**
+   * The total length of input_data
+   */
+  int input_total;
+
+  /**
+   * K3ProcessController is a friend of K3Process because it has to have
+   * access to various data members.
+   */
+  friend class K3ProcessController;
+
+private:
+  K3ProcessPrivate* const d;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(K3Process::Communication)
+
+class K3ShellProcessPrivate;
+
+/**
+* @obsolete
+*
+* Use K3Process and K3Process::setUseShell(true) instead.
+*
+*   @short A class derived from K3Process to start child
+*   	processes through a shell.
+*   @author Christian Czezatke <e9025461@student.tuwien.ac.at>
+*/
+class K3ShellProcess : public K3Process
+{
+  Q_OBJECT
+
+public:
+
+  /**
+   * Constructor
+   *
+   * If no shellname is specified, the user's default shell is used.
+   */
+  explicit K3ShellProcess(const char *shellname=0);
+
+  /**
+   * Destructor.
+   */
+  ~K3ShellProcess();
+
+  virtual bool start(RunMode  runmode = NotifyOnExit,
+		  Communication comm = NoCommunication);
+
+  static QString quote(const QString &arg);
+
+private:
+  K3ShellProcessPrivate* const d;
+};
+
+
+
+#endif
+
new file mode 100644
--- /dev/null
+++ b/gui//k3processcontroller.cpp
@@ -0,0 +1,334 @@
+/* This file is part of the KDE libraries
+    Copyright (C) 1997 Christian Czezakte (e9025461@student.tuwien.ac.at)
+
+    Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public License
+    along with this library; see the file COPYING.LIB.  If not, write to
+    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+    Boston, MA 02110-1301, USA.
+*/
+
+#include "k3processcontroller.h"
+#include "k3process.h"
+
+//#include <config.h>
+
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <QtCore/QSocketNotifier>
+
+class K3ProcessController::Private
+{
+public:
+    Private()
+        : needcheck( false ),
+          notifier( 0 )
+    {
+    }
+
+    ~Private()
+    {
+        delete notifier;
+    }
+
+    int fd[2];
+    bool needcheck;
+    QSocketNotifier *notifier;
+    QList<K3Process*> kProcessList;
+    QList<int> unixProcessList;
+    static struct sigaction oldChildHandlerData;
+    static bool handlerSet;
+    static int refCount;
+    static K3ProcessController* instance;
+};
+
+K3ProcessController *K3ProcessController::Private::instance = 0;
+int K3ProcessController::Private::refCount = 0;
+
+void K3ProcessController::ref()
+{
+    if ( !Private::refCount ) {
+        Private::instance = new K3ProcessController;
+        setupHandlers();
+    }
+    Private::refCount++;
+}
+
+void K3ProcessController::deref()
+{
+    Private::refCount--;
+    if( !Private::refCount ) {
+        resetHandlers();
+        delete Private::instance;
+        Private::instance = 0;
+    }
+}
+
+K3ProcessController* K3ProcessController::instance()
+{
+    /*
+     * there were no safety guards in previous revisions, is that ok?
+    if ( !Private::instance ) {
+        ref();
+    }
+     */
+
+    return Private::instance;
+}
+
+K3ProcessController::K3ProcessController()
+  : d( new Private )
+{
+  if( pipe( d->fd ) )
+  {
+    perror( "pipe" );
+    abort();
+  }
+
+  fcntl( d->fd[0], F_SETFL, O_NONBLOCK ); // in case slotDoHousekeeping is called without polling first
+  fcntl( d->fd[1], F_SETFL, O_NONBLOCK ); // in case it fills up
+  fcntl( d->fd[0], F_SETFD, FD_CLOEXEC );
+  fcntl( d->fd[1], F_SETFD, FD_CLOEXEC );
+
+  d->notifier = new QSocketNotifier( d->fd[0], QSocketNotifier::Read );
+  d->notifier->setEnabled( true );
+  QObject::connect( d->notifier, SIGNAL(activated(int)),
+                    SLOT(slotDoHousekeeping()));
+}
+
+K3ProcessController::~K3ProcessController()
+{
+#ifndef Q_OS_MAC
+/* not sure why, but this is causing lockups */
+  close( d->fd[0] );
+  close( d->fd[1] );
+#else
+#warning FIXME: why does close() freeze up destruction?
+#endif
+
+  delete d;
+}
+
+
+extern "C" {
+static void theReaper( int num )
+{
+  K3ProcessController::theSigCHLDHandler( num );
+}
+}
+
+#ifdef Q_OS_UNIX
+struct sigaction K3ProcessController::Private::oldChildHandlerData;
+#endif
+bool K3ProcessController::Private::handlerSet = false;
+
+void K3ProcessController::setupHandlers()
+{
+  if( Private::handlerSet )
+      return;
+  Private::handlerSet = true;
+
+#ifdef Q_OS_UNIX
+  struct sigaction act;
+  sigemptyset( &act.sa_mask );
+
+  act.sa_handler = SIG_IGN;
+  act.sa_flags = 0;
+  sigaction( SIGPIPE, &act, 0L );
+
+  act.sa_handler = theReaper;
+  act.sa_flags = SA_NOCLDSTOP;
+  // CC: take care of SunOS which automatically restarts interrupted system
+  // calls (and thus does not have SA_RESTART)
+#ifdef SA_RESTART
+  act.sa_flags |= SA_RESTART;
+#endif
+  sigaction( SIGCHLD, &act, &Private::oldChildHandlerData );
+
+  sigaddset( &act.sa_mask, SIGCHLD );
+  // Make sure we don't block this signal. gdb tends to do that :-(
+  sigprocmask( SIG_UNBLOCK, &act.sa_mask, 0 );
+#else
+  //TODO: win32
+#endif
+}
+
+void K3ProcessController::resetHandlers()
+{
+  if( !Private::handlerSet )
+      return;
+  Private::handlerSet = false;
+
+#ifdef Q_OS_UNIX
+  sigset_t mask, omask;
+  sigemptyset( &mask );
+  sigaddset( &mask, SIGCHLD );
+  sigprocmask( SIG_BLOCK, &mask, &omask );
+
+  struct sigaction act;
+  sigaction( SIGCHLD, &Private::oldChildHandlerData, &act );
+  if (act.sa_handler != theReaper) {
+     sigaction( SIGCHLD, &act, 0 );
+     Private::handlerSet = true;
+  }
+
+  sigprocmask( SIG_SETMASK, &omask, 0 );
+#else
+  //TODO: win32
+#endif
+  // there should be no problem with SIGPIPE staying SIG_IGN
+}
+
+// the pipe is needed to sync the child reaping with our event processing,
+// as otherwise there are race conditions, locking requirements, and things
+// generally get harder
+void K3ProcessController::theSigCHLDHandler( int arg )
+{
+  int saved_errno = errno;
+
+  char dummy = 0;
+  ::write( instance()->d->fd[1], &dummy, 1 );
+
+#ifdef Q_OS_UNIX
+    if ( Private::oldChildHandlerData.sa_handler != SIG_IGN &&
+         Private::oldChildHandlerData.sa_handler != SIG_DFL ) {
+        Private::oldChildHandlerData.sa_handler( arg ); // call the old handler
+    }
+#else
+  //TODO: win32
+#endif
+
+  errno = saved_errno;
+}
+
+int K3ProcessController::notifierFd() const
+{
+  return d->fd[0];
+}
+
+void K3ProcessController::unscheduleCheck()
+{
+  char dummy[16]; // somewhat bigger - just in case several have queued up
+  if( ::read( d->fd[0], dummy, sizeof(dummy) ) > 0 )
+    d->needcheck = true;
+}
+
+void
+K3ProcessController::rescheduleCheck()
+{
+  if( d->needcheck )
+  {
+    d->needcheck = false;
+    char dummy = 0;
+    ::write( d->fd[1], &dummy, 1 );
+  }
+}
+
+void K3ProcessController::slotDoHousekeeping()
+{
+  char dummy[16]; // somewhat bigger - just in case several have queued up
+  ::read( d->fd[0], dummy, sizeof(dummy) );
+
+  int status;
+ again:
+  QList<K3Process*>::iterator it( d->kProcessList.begin() );
+  QList<K3Process*>::iterator eit( d->kProcessList.end() );
+  while( it != eit )
+  {
+    K3Process *prc = *it;
+    if( prc->runs && waitpid( prc->pid_, &status, WNOHANG ) > 0 )
+    {
+      prc->processHasExited( status );
+      // the callback can nuke the whole process list and even 'this'
+      if (!instance())
+        return;
+      goto again;
+    }
+    ++it;
+  }
+  QList<int>::iterator uit( d->unixProcessList.begin() );
+  QList<int>::iterator ueit( d->unixProcessList.end() );
+  while( uit != ueit )
+  {
+    if( waitpid( *uit, 0, WNOHANG ) > 0 )
+    {
+      uit = d->unixProcessList.erase( uit );
+      deref(); // counterpart to addProcess, can invalidate 'this'
+    } else
+      ++uit;
+  }
+}
+
+bool K3ProcessController::waitForProcessExit( int timeout )
+{
+#ifdef Q_OS_UNIX
+  for(;;)
+  {
+    struct timeval tv, *tvp;
+    if (timeout < 0)
+      tvp = 0;
+    else
+    {
+      tv.tv_sec = timeout;
+      tv.tv_usec = 0;
+      tvp = &tv;
+    }
+
+    fd_set fds;
+    FD_ZERO( &fds );
+    FD_SET( d->fd[0], &fds );
+
+    switch( select( d->fd[0]+1, &fds, 0, 0, tvp ) )
+    {
+    case -1:
+      if( errno == EINTR )
+        continue;
+      // fall through; should never happen
+    case 0:
+      return false;
+    default:
+      slotDoHousekeeping();
+      return true;
+    }
+  }
+#else
+  //TODO: win32
+  return false;
+#endif
+}
+
+void K3ProcessController::addKProcess( K3Process* p )
+{
+  d->kProcessList.append( p );
+}
+
+void K3ProcessController::removeKProcess( K3Process* p )
+{
+  d->kProcessList.removeAll( p );
+}
+
+void K3ProcessController::addProcess( int pid )
+{
+  d->unixProcessList.append( pid );
+  ref(); // make sure we stay around when the K3Process goes away
+}
+
+//#include "moc_k3processcontroller.cpp"
new file mode 100644
--- /dev/null
+++ b/gui//k3processcontroller.h
@@ -0,0 +1,137 @@
+/* This file is part of the KDE libraries
+    Copyright (C) 1997 Christian Czezakte (e9025461@student.tuwien.ac.at)
+
+    Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public License
+    along with this library; see the file COPYING.LIB.  If not, write to
+    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+    Boston, MA 02110-1301, USA.
+*/
+
+#ifndef K3PROCCTRL_H
+#define K3PROCCTRL_H
+
+#include <QtCore/QList>
+#include <k3process.h>
+
+
+/**
+ * @short Used internally by K3Process
+ * @internal
+ * @author Christian Czezatke <e9025461@student.tuwien.ac.at>
+ *
+ *  A class for internal use by K3Process only. -- Exactly one instance
+ *  of this class is created by KApplication.
+ *
+ * This class takes care of the actual (UN*X) signal handling.
+ */
+class K3ProcessController : public QObject
+{
+  Q_OBJECT
+
+public:
+  /**
+   * Create an instance if none exists yet.
+   * Called by KApplication::KApplication()
+   */
+  static void ref();
+
+  /**
+   * Destroy the instance if one exists and it is not referenced any more.
+   * Called by KApplication::~KApplication()
+   */
+  static void deref();
+
+  /**
+   * Only a single instance of this class is allowed at a time.
+   * This method provides access to that instance.
+   */
+  static K3ProcessController *instance();
+
+  /**
+   * Automatically called upon SIGCHLD. Never call it directly.
+   * If your application (or some library it uses) redirects SIGCHLD,
+   * the new signal handler (and only it) should call the old handler
+   * returned by sigaction().
+   * @internal
+   */
+  static void theSigCHLDHandler(int signal); // KDE4: private
+
+  /**
+   * Wait for any process to exit and handle their exit without
+   * starting an event loop.
+   * This function may cause K3Process to emit any of its signals.
+   *
+   * @param timeout the timeout in seconds. -1 means no timeout.
+   * @return true if a process exited, false
+   *         if no process exited within @p timeout seconds.
+   */
+  bool waitForProcessExit(int timeout);
+
+  /**
+   * Call this function to defer processing of the data that became available
+   * on notifierFd().
+   */
+  void unscheduleCheck();
+
+  /**
+   * This function @em must be called at some point after calling
+   * unscheduleCheck().
+   */
+  void rescheduleCheck();
+
+  /*
+   * Obtain the file descriptor K3ProcessController uses to get notified
+   * about process exits. select() or poll() on it if you create a custom
+   * event loop that needs to act upon SIGCHLD.
+   * @return the file descriptor of the reading end of the notification pipe
+   */
+  int notifierFd() const;
+
+  /**
+   * @internal
+   */
+  void addKProcess( K3Process* );
+  /**
+   * @internal
+   */
+  void removeKProcess( K3Process* );
+  /**
+   * @internal
+   */
+  void addProcess( int pid );
+
+private Q_SLOTS:
+  void slotDoHousekeeping();
+
+private:
+  friend class I_just_love_gcc;
+
+  static void setupHandlers();
+  static void resetHandlers();
+
+  // Disallow instantiation
+  K3ProcessController();
+  ~K3ProcessController();
+
+  // Disallow assignment and copy-construction
+  K3ProcessController( const K3ProcessController& );
+  K3ProcessController& operator= ( const K3ProcessController& );
+
+  class Private;
+  Private * const d;
+};
+
+#endif
+
new file mode 100644
--- /dev/null
+++ b/gui//kb-layouts/CVS/Entries
@@ -0,0 +1,4 @@
+/default.keytab/1.1.1.1/Sat May 10 21:27:57 2008//
+/linux.keytab/1.1.1.1/Sat May 10 21:27:57 2008//
+/vt420pc.keytab/1.1.1.1/Sat May 10 21:27:57 2008//
+D
new file mode 100644
--- /dev/null
+++ b/gui//kb-layouts/CVS/Repository
@@ -0,0 +1,1 @@
+qtermwidget/lib/kb-layouts
new file mode 100644
--- /dev/null
+++ b/gui//kb-layouts/CVS/Root
@@ -0,0 +1,1 @@
+:ext:e_k@qtermwidget.cvs.sourceforge.net:/cvsroot/qtermwidget
new file mode 100644
--- /dev/null
+++ b/gui//kb-layouts/default.keytab
@@ -0,0 +1,133 @@
+# [README.default.Keytab] Buildin Keyboard Table
+#
+# To customize your keyboard, copy this file to something
+# ending with .keytab and change it to meet you needs.
+# Please read the README.KeyTab and the README.keyboard
+# in this case.
+#
+# --------------------------------------------------------------
+
+keyboard "Default (XFree 4)"
+
+# --------------------------------------------------------------
+#
+# Note that this particular table is a "risc" version made to
+# ease customization without bothering with obsolete details.
+# See VT100.keytab for the more hairy stuff.
+#
+# --------------------------------------------------------------
+
+# common keys
+
+key Escape             : "\E"
+
+key Tab   -Shift       : "\t"
+key Tab   +Shift+Ansi  : "\E[Z"
+key Tab   +Shift-Ansi  : "\t"
+key Backtab     +Ansi  : "\E[Z"
+key Backtab     -Ansi  : "\t"
+
+key Return-Shift-NewLine : "\r"
+key Return-Shift+NewLine : "\r\n"
+
+key Return+Shift         : "\EOM"
+
+# Backspace and Delete codes are preserving CTRL-H.
+
+key Backspace      : "\x7f"
+
+# Arrow keys in VT52 mode
+# shift up/down are reserved for scrolling.
+# shift left/right are reserved for switching between tabs (this is hardcoded).
+
+key Up   -Shift-Ansi : "\EA"
+key Down -Shift-Ansi : "\EB"
+key Right-Shift-Ansi : "\EC"
+key Left -Shift-Ansi : "\ED"
+
+# Arrow keys in ANSI mode with Application - and Normal Cursor Mode)
+
+key Up    -Shift-AnyMod+Ansi+AppCuKeys           : "\EOA"
+key Down  -Shift-AnyMod+Ansi+AppCuKeys           : "\EOB"
+key Right -Shift-AnyMod+Ansi+AppCuKeys           : "\EOC"
+key Left  -Shift-AnyMod+Ansi+AppCuKeys           : "\EOD"
+
+key Up    -Shift-AnyMod+Ansi-AppCuKeys           : "\E[A"
+key Down  -Shift-AnyMod+Ansi-AppCuKeys           : "\E[B"
+key Right -Shift-AnyMod+Ansi-AppCuKeys           : "\E[C"
+key Left  -Shift-AnyMod+Ansi-AppCuKeys           : "\E[D"
+
+key Up    -Shift+AnyMod+Ansi                     : "\E[1;*A"
+key Down  -Shift+AnyMod+Ansi                     : "\E[1;*B"
+key Right -Shift+AnyMod+Ansi                     : "\E[1;*C"
+key Left  -Shift+AnyMod+Ansi                     : "\E[1;*D"
+
+# other grey PC keys
+
+key Enter+NewLine : "\r\n"
+key Enter-NewLine : "\r"
+
+key Home        -AnyMod     -AppCuKeys           : "\E[H"  
+key End         -AnyMod     -AppCuKeys           : "\E[F"  
+key Home        -AnyMod     +AppCuKeys           : "\EOH"  
+key End         -AnyMod     +AppCuKeys           : "\EOF"  
+key Home        +AnyMod                          : "\E[1;*H"
+key End         +AnyMod                          : "\E[1;*F"
+
+key Insert      -AnyMod                          : "\E[2~"
+key Delete      -AnyMod                          : "\E[3~"
+key Insert      +AnyMod                          : "\E[2;*~"
+key Delete      +AnyMod                          : "\E[3;*~"
+
+key Prior -Shift-AnyMod                          : "\E[5~"
+key Next  -Shift-AnyMod                          : "\E[6~"
+key Prior -Shift+AnyMod                          : "\E[5;*~"
+key Next  -Shift+AnyMod                          : "\E[6;*~"
+
+# Function keys
+key F1          -AnyMod                          : "\EOP"
+key F2          -AnyMod                          : "\EOQ"
+key F3          -AnyMod                          : "\EOR"
+key F4          -AnyMod                          : "\EOS"
+key F5          -AnyMod                          : "\E[15~"
+key F6          -AnyMod                          : "\E[17~"
+key F7          -AnyMod                          : "\E[18~"
+key F8          -AnyMod                          : "\E[19~"
+key F9          -AnyMod                          : "\E[20~"
+key F10         -AnyMod                          : "\E[21~"
+key F11         -AnyMod                          : "\E[23~"
+key F12         -AnyMod                          : "\E[24~"
+
+key F1          +AnyMod                          : "\EO*P"
+key F2          +AnyMod                          : "\EO*Q"
+key F3          +AnyMod                          : "\EO*R"
+key F4          +AnyMod                          : "\EO*S"
+key F5          +AnyMod                          : "\E[15;*~"
+key F6          +AnyMod                          : "\E[17;*~"
+key F7          +AnyMod                          : "\E[18;*~"
+key F8          +AnyMod                          : "\E[19;*~"
+key F9          +AnyMod                          : "\E[20;*~"
+key F10         +AnyMod                          : "\E[21;*~"
+key F11         +AnyMod                          : "\E[23;*~"
+key F12         +AnyMod                          : "\E[24;*~"
+
+# Work around dead keys
+
+key Space +Control : "\x00"
+
+# Some keys are used by konsole to cause operations.
+# The scroll* operations refer to the history buffer.
+
+key Up    +Shift-AppScreen  : scrollLineUp
+key Prior +Shift-AppScreen  : scrollPageUp
+key Down  +Shift-AppScreen  : scrollLineDown
+key Next  +Shift-AppScreen  : scrollPageDown
+
+#key Up    +Shift  : scrollLineUp
+#key Prior +Shift  : scrollPageUp
+#key Down  +Shift  : scrollLineDown
+#key Next  +Shift  : scrollPageDown
+
+key ScrollLock     : scrollLock
+
+# keypad characters are not offered differently by Qt.
new file mode 100644
--- /dev/null
+++ b/gui//kb-layouts/linux.keytab
@@ -0,0 +1,133 @@
+# [linux.keytab] Konsole Keyboard Table (Linux console keys)
+#
+# --------------------------------------------------------------
+
+# NOT TESTED, MAY NEED SOME CLEANUPS
+keyboard "Linux console"
+
+# --------------------------------------------------------------
+#
+# This configuration table allows to customize the
+# meaning of the keys.
+#
+# The syntax is that each entry has the form : 
+#
+#   "key" Keyname { ("+"|"-") Modename } ":" (String|Operation)
+#
+# Keynames are those defined in <qnamespace.h> with the
+# "Qt::Key_" removed. (We'd better insert the list here)
+#
+# Mode names are : 
+#
+# - Shift
+# - Alt
+# - Control
+#
+#   The VT100 emulation has two modes that can affect the
+#   sequences emitted by certain keys. These modes are
+#   under control of the client program.
+#   
+# - Newline     : effects Return and Enter key.
+# - Application : effects Up and Down key.
+#
+# - Ansi        : effects Up and Down key (This is for VT52, really).
+#
+# Operations are
+#
+# - scrollUpLine
+# - scrollUpPage
+# - scrollDownLine
+# - scrollDownPage
+#
+# - emitSelection
+#
+# If the key is not found here, the text of the
+# key event as provided by QT is emitted, possibly
+# preceeded by ESC if the Alt key is pressed.
+#
+# --------------------------------------------------------------
+
+key Escape : "\E"
+key Tab    : "\t"
+
+# VT100 can add an extra \n after return.
+# The NewLine mode is set by an escape sequence.
+
+key Return-NewLine : "\r"  
+key Return+NewLine : "\r\n"
+
+# Some desperately try to save the ^H.
+
+key Backspace : "\x7f"
+key Delete    : "\E[3~"
+
+# These codes are for the VT52 mode of VT100
+# The Ansi mode (i.e. VT100 mode) is set by
+# an escape sequence
+
+key Up   -Shift-Ansi : "\EA"
+key Down -Shift-Ansi : "\EB"
+key Right-Shift-Ansi : "\EC"
+key Left -Shift-Ansi : "\ED"
+
+# VT100 emits a mode bit together
+# with the arrow keys.The AppCuKeys
+# mode is set by an escape sequence.
+
+key Up   -Shift+Ansi+AppCuKeys : "\EOA"
+key Down -Shift+Ansi+AppCuKeys : "\EOB"
+key Right-Shift+Ansi+AppCuKeys : "\EOC"
+key Left -Shift+Ansi+AppCuKeys : "\EOD"
+
+key Up   -Shift+Ansi-AppCuKeys : "\E[A"
+key Down -Shift+Ansi-AppCuKeys : "\E[B"
+key Right-Shift+Ansi-AppCuKeys : "\E[C"
+key Left -Shift+Ansi-AppCuKeys : "\E[D"
+
+# linux functions keys F1-F5 differ from xterm
+
+key F1 : "\E[[A" 
+key F2 : "\E[[B" 
+key F3 : "\E[[C" 
+key F4 : "\E[[D" 
+key F5 : "\E[[E" 
+
+key F6     : "\E[17~" 
+key F7     : "\E[18~" 
+key F8     : "\E[19~" 
+key F9     : "\E[20~" 
+key F10    : "\E[21~" 
+key F11    : "\E[23~" 
+key F12    : "\E[24~" 
+
+key Home   : "\E[1~"  
+key End    : "\E[4~"  
+
+key Prior -Shift : "\E[5~"  
+key Next  -Shift : "\E[6~"  
+key Insert-Shift : "\E[2~"  
+
+# Keypad-Enter. See comment on Return above.
+
+key Enter+NewLine : "\r\n"
+key Enter-NewLine : "\r"  
+
+key Space +Control : "\x00"
+
+# some of keys are used by konsole.
+
+key Up    +Shift   : scrollLineUp
+key Prior +Shift   : scrollPageUp
+key Down  +Shift   : scrollLineDown
+key Next  +Shift   : scrollPageDown
+
+key ScrollLock     : scrollLock
+
+#----------------------------------------------------------
+
+# keypad characters as offered by Qt
+# cannot be recognized as such.
+
+#----------------------------------------------------------
+
+# Following other strings as emitted by konsole.
new file mode 100644
--- /dev/null
+++ b/gui//kb-layouts/vt420pc.keytab
@@ -0,0 +1,163 @@
+# [vt420pc.keytab] Konsole Keyboard Table (VT420pc keys)
+# adapted by ferdinand gassauer f.gassauer@aon.at
+# Nov 2000
+#
+################################################################
+#
+# The escape sequences emmited by the 
+# keys Shift+F1 to Shift+F12 might not fit your needs
+#
+################# IMPORTANT NOTICE #############################
+# the key bindings (Kcontrol -> look and feel -> keybindgs) 
+# overrule the settings in this file. The key bindings might be 
+# changed by the user WITHOUT notification of the maintainer of
+# the keytab file. Konsole will not work as expected by 
+# the maintainer of the keytab file.
+################################################################
+#
+# --------------------------------------------------------------
+
+keyboard "DEC VT420 Terminal"
+
+# --------------------------------------------------------------
+#
+# This configuration table allows to customize the
+# meaning of the keys.
+#
+# The syntax is that each entry has the form : 
+#
+#   "key" Keyname { ("+"|"-") Modename } ":" (String|Operation)
+#
+# Keynames are those defined in <qnamespace.h> with the
+# "Qt::Key_" removed. (We'd better insert the list here)
+#
+# Mode names are : 
+#
+# - Shift
+# - Alt
+# - Control
+#
+#   The VT100 emulation has two modes that can affect the
+#   sequences emitted by certain keys. These modes are
+#   under control of the client program.
+#   
+# - Newline     : effects Return and Enter key.
+# - Application : effects Up and Down key.
+#
+# - Ansi        : effects Up and Down key (This is for VT52, really).
+#
+# Operations are
+#
+# - scrollUpLine
+# - scrollUpPage
+# - scrollDownLine
+# - scrollDownPage
+#
+# - emitSelection
+#
+# If the key is not found here, the text of the
+# key event as provided by QT is emitted, possibly
+# preceeded by ESC if the Alt key is pressed.
+#
+# --------------------------------------------------------------
+
+key Escape : "\E"
+key Tab    : "\t"
+key Backtab: "\E[Z"
+
+# VT100 can add an extra \n after return.
+# The NewLine mode is set by an escape sequence.
+
+key Return-NewLine : "\r"  
+key Return+NewLine : "\r\n"
+
+# Some desperately try to save the ^H.
+# may be not everyone wants this
+
+key Backspace : "\x08"  # Control H
+key Delete    : "\x7f"
+
+# These codes are for the VT420pc
+# The Ansi mode (i.e. VT100 mode) is set by
+# an escape sequence
+
+key Up   -Shift-Ansi : "\EA"
+key Down -Shift-Ansi : "\EB"
+key Right-Shift-Ansi : "\EC"
+key Left -Shift-Ansi : "\ED"
+
+# VT100 emits a mode bit together
+# with the arrow keys.The AppCuKeys
+# mode is set by an escape sequence.
+
+key Up   -Shift+Ansi+AppCuKeys : "\EOA"
+key Down -Shift+Ansi+AppCuKeys : "\EOB"
+key Right-Shift+Ansi+AppCuKeys : "\EOC"
+key Left -Shift+Ansi+AppCuKeys : "\EOD"
+
+key Up   -Shift+Ansi-AppCuKeys : "\E[A"
+key Down -Shift+Ansi-AppCuKeys : "\E[B"
+key Right-Shift+Ansi-AppCuKeys : "\E[C"
+key Left -Shift+Ansi-AppCuKeys : "\E[D"
+
+# function keys 
+
+key F1 -Shift    : "\E[11~"  
+key F2 -Shift    : "\E[12~"
+key F3 -Shift    : "\E[13~"
+key F4 -Shift    : "\E[14~"
+key F5 -Shift    : "\E[15~"
+key F6 -Shift    : "\E[17~"
+key F7 -Shift    : "\E[18~"
+key F8 -Shift    : "\E[19~"
+key F9 -Shift    : "\E[20~"
+key F10-Shift    : "\E[21~"
+key F11-Shift    : "\E[23~"
+key F12-Shift    : "\E[24~"  
+#
+# Shift F1-F12
+#
+key F1 +Shift    : "\E[11;2~"
+key F2 +Shift    : "\E[12;2~"
+key F3 +Shift    : "\E[13;2~"
+key F4 +Shift    : "\E[14;2~"
+key F5 +Shift    : "\E[15;2~"
+key F6 +Shift    : "\E[17;2~" 
+key F7 +Shift    : "\E[18;2~" 
+key F8 +Shift    : "\E[19;2~" 
+key F9 +Shift    : "\E[20;2~" 
+key F10+Shift    : "\E[21;2~" 
+key F11+Shift    : "\E[23;2~" 
+key F12+Shift    : "\E[24;2~" 
+
+key Home   : "\E[H"  
+key End    : "\E[F"  
+
+key Prior -Shift : "\E[5~"  
+key Next  -Shift : "\E[6~"  
+key Insert-Shift : "\E[2~"  
+
+# Keypad-Enter. See comment on Return above.
+
+key Enter+NewLine : "\r\n"
+key Enter-NewLine : "\r"  
+
+key Space +Control : "\x00"
+
+# some of keys are used by konsole.
+
+key Up    +Shift   : scrollLineUp
+key Prior +Shift   : scrollPageUp
+key Down  +Shift   : scrollLineDown
+key Next  +Shift   : scrollPageDown
+
+key ScrollLock     : scrollLock
+
+#----------------------------------------------------------
+
+# keypad characters as offered by Qt
+# cannot be recognized as such.
+
+#----------------------------------------------------------
+
+# Following other strings as emitted by konsole.
new file mode 100644
--- /dev/null
+++ b/gui//konsole_wcwidth.cpp
@@ -0,0 +1,216 @@
+/* $XFree86: xc/programs/xterm/wcwidth.character,v 1.3 2001/07/29 22:08:16 tsi Exp $ */
+/*
+ * This is an implementation of wcwidth() and wcswidth() as defined in
+ * "The Single UNIX Specification, Version 2, The Open Group, 1997"
+ * <http://www.UNIX-systems.org/online.html>
+ *
+ * Markus Kuhn -- 2001-01-12 -- public domain
+ */
+
+#include "konsole_wcwidth.h"
+
+struct interval {
+  unsigned short first;
+  unsigned short last;
+};
+
+/* auxiliary function for binary search in interval table */
+static int bisearch(quint16 ucs, const struct interval *table, int max) {
+  int min = 0;
+  int mid;
+
+  if (ucs < table[0].first || ucs > table[max].last)
+    return 0;
+  while (max >= min) {
+    mid = (min + max) / 2;
+    if (ucs > table[mid].last)
+      min = mid + 1;
+    else if (ucs < table[mid].first)
+      max = mid - 1;
+    else
+      return 1;
+  }
+
+  return 0;
+}
+
+
+/* The following functions define the column width of an ISO 10646
+ * character as follows:
+ *
+ *    - The null character (U+0000) has a column width of 0.
+ *
+ *    - Other C0/C1 control characters and DEL will lead to a return
+ *      value of -1.
+ *
+ *    - Non-spacing and enclosing combining characters (general
+ *      category code Mn or Me in the Unicode database) have a
+ *      column width of 0.
+ *
+ *    - Other format characters (general category code Cf in the Unicode
+ *      database) and ZERO WIDTH SPACE (U+200B) have a column width of 0.
+ *
+ *    - Hangul Jamo medial vowels and final consonants (U+1160-U+11FF)
+ *      have a column width of 0.
+ *
+ *    - Spacing characters in the East Asian Wide (W) or East Asian
+ *      FullWidth (F) category as defined in Unicode Technical
+ *      Report #11 have a column width of 2.
+ *
+ *    - All remaining characters (including all printable
+ *      ISO 8859-1 and WGL4 characters, Unicode control characters,
+ *      etc.) have a column width of 1.
+ *
+ * This implementation assumes that quint16 characters are encoded
+ * in ISO 10646.
+ */
+
+int konsole_wcwidth(quint16 ucs)
+{
+  /* sorted list of non-overlapping intervals of non-spacing characters */
+  static const struct interval combining[] = {
+    { 0x0300, 0x034E }, { 0x0360, 0x0362 }, { 0x0483, 0x0486 },
+    { 0x0488, 0x0489 }, { 0x0591, 0x05A1 }, { 0x05A3, 0x05B9 },
+    { 0x05BB, 0x05BD }, { 0x05BF, 0x05BF }, { 0x05C1, 0x05C2 },
+    { 0x05C4, 0x05C4 }, { 0x064B, 0x0655 }, { 0x0670, 0x0670 },
+    { 0x06D6, 0x06E4 }, { 0x06E7, 0x06E8 }, { 0x06EA, 0x06ED },
+    { 0x070F, 0x070F }, { 0x0711, 0x0711 }, { 0x0730, 0x074A },
+    { 0x07A6, 0x07B0 }, { 0x0901, 0x0902 }, { 0x093C, 0x093C },
+    { 0x0941, 0x0948 }, { 0x094D, 0x094D }, { 0x0951, 0x0954 },
+    { 0x0962, 0x0963 }, { 0x0981, 0x0981 }, { 0x09BC, 0x09BC },
+    { 0x09C1, 0x09C4 }, { 0x09CD, 0x09CD }, { 0x09E2, 0x09E3 },
+    { 0x0A02, 0x0A02 }, { 0x0A3C, 0x0A3C }, { 0x0A41, 0x0A42 },
+    { 0x0A47, 0x0A48 }, { 0x0A4B, 0x0A4D }, { 0x0A70, 0x0A71 },
+    { 0x0A81, 0x0A82 }, { 0x0ABC, 0x0ABC }, { 0x0AC1, 0x0AC5 },
+    { 0x0AC7, 0x0AC8 }, { 0x0ACD, 0x0ACD }, { 0x0B01, 0x0B01 },
+    { 0x0B3C, 0x0B3C }, { 0x0B3F, 0x0B3F }, { 0x0B41, 0x0B43 },
+    { 0x0B4D, 0x0B4D }, { 0x0B56, 0x0B56 }, { 0x0B82, 0x0B82 },
+    { 0x0BC0, 0x0BC0 }, { 0x0BCD, 0x0BCD }, { 0x0C3E, 0x0C40 },
+    { 0x0C46, 0x0C48 }, { 0x0C4A, 0x0C4D }, { 0x0C55, 0x0C56 },
+    { 0x0CBF, 0x0CBF }, { 0x0CC6, 0x0CC6 }, { 0x0CCC, 0x0CCD },
+    { 0x0D41, 0x0D43 }, { 0x0D4D, 0x0D4D }, { 0x0DCA, 0x0DCA },
+    { 0x0DD2, 0x0DD4 }, { 0x0DD6, 0x0DD6 }, { 0x0E31, 0x0E31 },
+    { 0x0E34, 0x0E3A }, { 0x0E47, 0x0E4E }, { 0x0EB1, 0x0EB1 },
+    { 0x0EB4, 0x0EB9 }, { 0x0EBB, 0x0EBC }, { 0x0EC8, 0x0ECD },
+    { 0x0F18, 0x0F19 }, { 0x0F35, 0x0F35 }, { 0x0F37, 0x0F37 },
+    { 0x0F39, 0x0F39 }, { 0x0F71, 0x0F7E }, { 0x0F80, 0x0F84 },
+    { 0x0F86, 0x0F87 }, { 0x0F90, 0x0F97 }, { 0x0F99, 0x0FBC },
+    { 0x0FC6, 0x0FC6 }, { 0x102D, 0x1030 }, { 0x1032, 0x1032 },
+    { 0x1036, 0x1037 }, { 0x1039, 0x1039 }, { 0x1058, 0x1059 },
+    { 0x1160, 0x11FF }, { 0x17B7, 0x17BD }, { 0x17C6, 0x17C6 },
+    { 0x17C9, 0x17D3 }, { 0x180B, 0x180E }, { 0x18A9, 0x18A9 },
+    { 0x200B, 0x200F }, { 0x202A, 0x202E }, { 0x206A, 0x206F },
+    { 0x20D0, 0x20E3 }, { 0x302A, 0x302F }, { 0x3099, 0x309A },
+    { 0xFB1E, 0xFB1E }, { 0xFE20, 0xFE23 }, { 0xFEFF, 0xFEFF },
+    { 0xFFF9, 0xFFFB }
+  };
+
+  /* test for 8-bit control characters */
+  if (ucs == 0)
+    return 0;
+  if (ucs < 32 || (ucs >= 0x7f && ucs < 0xa0))
+    return -1;
+
+  /* binary search in table of non-spacing characters */
+  if (bisearch(ucs, combining,
+	       sizeof(combining) / sizeof(struct interval) - 1))
+    return 0;
+
+  /* if we arrive here, ucs is not a combining or C0/C1 control character */
+
+  return 1 +
+    (ucs >= 0x1100 &&
+     (ucs <= 0x115f ||                    /* Hangul Jamo init. consonants */
+      (ucs >= 0x2e80 && ucs <= 0xa4cf && (ucs & ~0x0011) != 0x300a &&
+       ucs != 0x303f) ||                  /* CJK ... Yi */
+      (ucs >= 0xac00 && ucs <= 0xd7a3) || /* Hangul Syllables */
+      (ucs >= 0xf900 && ucs <= 0xfaff) || /* CJK Compatibility Ideographs */
+      (ucs >= 0xfe30 && ucs <= 0xfe6f) || /* CJK Compatibility Forms */
+      (ucs >= 0xff00 && ucs <= 0xff5f) || /* Fullwidth Forms */
+      (ucs >= 0xffe0 && ucs <= 0xffe6) /* do not compare UINT16 with 0x20000 ||
+      (ucs >= 0x20000 && ucs <= 0x2ffff) */));
+}
+
+#if 0
+/*
+ * The following function is the same as konsole_wcwidth(), except that
+ * spacing characters in the East Asian Ambiguous (A) category as
+ * defined in Unicode Technical Report #11 have a column width of 2.
+ * This experimental variant might be useful for users of CJK legacy
+ * encodings who want to migrate to UCS. It is not otherwise
+ * recommended for general use.
+ */
+int konsole_wcwidth_cjk(quint16 ucs)
+{
+  /* sorted list of non-overlapping intervals of East Asian Ambiguous
+   * characters */
+  static const struct interval ambiguous[] = {
+    { 0x00A1, 0x00A1 }, { 0x00A4, 0x00A4 }, { 0x00A7, 0x00A8 },
+    { 0x00AA, 0x00AA }, { 0x00AD, 0x00AD }, { 0x00B0, 0x00B4 },
+    { 0x00B6, 0x00BA }, { 0x00BC, 0x00BF }, { 0x00C6, 0x00C6 },
+    { 0x00D0, 0x00D0 }, { 0x00D7, 0x00D8 }, { 0x00DE, 0x00E1 },
+    { 0x00E6, 0x00E6 }, { 0x00E8, 0x00EA }, { 0x00EC, 0x00ED },
+    { 0x00F0, 0x00F0 }, { 0x00F2, 0x00F3 }, { 0x00F7, 0x00FA },
+    { 0x00FC, 0x00FC }, { 0x00FE, 0x00FE }, { 0x0101, 0x0101 },
+    { 0x0111, 0x0111 }, { 0x0113, 0x0113 }, { 0x011B, 0x011B },
+    { 0x0126, 0x0127 }, { 0x012B, 0x012B }, { 0x0131, 0x0133 },
+    { 0x0138, 0x0138 }, { 0x013F, 0x0142 }, { 0x0144, 0x0144 },
+    { 0x0148, 0x014A }, { 0x014D, 0x014D }, { 0x0152, 0x0153 },
+    { 0x0166, 0x0167 }, { 0x016B, 0x016B }, { 0x01CE, 0x01CE },
+    { 0x01D0, 0x01D0 }, { 0x01D2, 0x01D2 }, { 0x01D4, 0x01D4 },
+    { 0x01D6, 0x01D6 }, { 0x01D8, 0x01D8 }, { 0x01DA, 0x01DA },
+    { 0x01DC, 0x01DC }, { 0x0251, 0x0251 }, { 0x0261, 0x0261 },
+    { 0x02C7, 0x02C7 }, { 0x02C9, 0x02CB }, { 0x02CD, 0x02CD },
+    { 0x02D0, 0x02D0 }, { 0x02D8, 0x02DB }, { 0x02DD, 0x02DD },
+    { 0x0391, 0x03A1 }, { 0x03A3, 0x03A9 }, { 0x03B1, 0x03C1 },
+    { 0x03C3, 0x03C9 }, { 0x0401, 0x0401 }, { 0x0410, 0x044F },
+    { 0x0451, 0x0451 }, { 0x2010, 0x2010 }, { 0x2013, 0x2016 },
+    { 0x2018, 0x2019 }, { 0x201C, 0x201D }, { 0x2020, 0x2021 },
+    { 0x2025, 0x2027 }, { 0x2030, 0x2030 }, { 0x2032, 0x2033 },
+    { 0x2035, 0x2035 }, { 0x203B, 0x203B }, { 0x2074, 0x2074 },
+    { 0x207F, 0x207F }, { 0x2081, 0x2084 }, { 0x20AC, 0x20AC },
+    { 0x2103, 0x2103 }, { 0x2105, 0x2105 }, { 0x2109, 0x2109 },
+    { 0x2113, 0x2113 }, { 0x2121, 0x2122 }, { 0x2126, 0x2126 },
+    { 0x212B, 0x212B }, { 0x2154, 0x2155 }, { 0x215B, 0x215B },
+    { 0x215E, 0x215E }, { 0x2160, 0x216B }, { 0x2170, 0x2179 },
+    { 0x2190, 0x2199 }, { 0x21D2, 0x21D2 }, { 0x21D4, 0x21D4 },
+    { 0x2200, 0x2200 }, { 0x2202, 0x2203 }, { 0x2207, 0x2208 },
+    { 0x220B, 0x220B }, { 0x220F, 0x220F }, { 0x2211, 0x2211 },
+    { 0x2215, 0x2215 }, { 0x221A, 0x221A }, { 0x221D, 0x2220 },
+    { 0x2223, 0x2223 }, { 0x2225, 0x2225 }, { 0x2227, 0x222C },
+    { 0x222E, 0x222E }, { 0x2234, 0x2237 }, { 0x223C, 0x223D },
+    { 0x2248, 0x2248 }, { 0x224C, 0x224C }, { 0x2252, 0x2252 },
+    { 0x2260, 0x2261 }, { 0x2264, 0x2267 }, { 0x226A, 0x226B },
+    { 0x226E, 0x226F }, { 0x2282, 0x2283 }, { 0x2286, 0x2287 },
+    { 0x2295, 0x2295 }, { 0x2299, 0x2299 }, { 0x22A5, 0x22A5 },
+    { 0x22BF, 0x22BF }, { 0x2312, 0x2312 }, { 0x2460, 0x24BF },
+    { 0x24D0, 0x24E9 }, { 0x2500, 0x254B }, { 0x2550, 0x2574 },
+    { 0x2580, 0x258F }, { 0x2592, 0x2595 }, { 0x25A0, 0x25A1 },
+    { 0x25A3, 0x25A9 }, { 0x25B2, 0x25B3 }, { 0x25B6, 0x25B7 },
+    { 0x25BC, 0x25BD }, { 0x25C0, 0x25C1 }, { 0x25C6, 0x25C8 },
+    { 0x25CB, 0x25CB }, { 0x25CE, 0x25D1 }, { 0x25E2, 0x25E5 },
+    { 0x25EF, 0x25EF }, { 0x2605, 0x2606 }, { 0x2609, 0x2609 },
+    { 0x260E, 0x260F }, { 0x261C, 0x261C }, { 0x261E, 0x261E },
+    { 0x2640, 0x2640 }, { 0x2642, 0x2642 }, { 0x2660, 0x2661 },
+    { 0x2663, 0x2665 }, { 0x2667, 0x266A }, { 0x266C, 0x266D },
+    { 0x266F, 0x266F }, { 0x300A, 0x300B }, { 0x301A, 0x301B },
+    { 0xE000, 0xF8FF }, { 0xFFFD, 0xFFFD }
+  };
+
+  /* binary search in table of non-spacing characters */
+  if (bisearch(ucs, ambiguous,
+	       sizeof(ambiguous) / sizeof(struct interval) - 1))
+    return 2;
+
+  return konsole_wcwidth(ucs);
+}
+#endif
+
+// single byte char: +1, multi byte char: +2
+int string_width( const QString &txt )
+{
+  int w = 0;
+  for ( int i = 0; i < txt.length(); ++i )
+     w += konsole_wcwidth( txt[ i ].unicode() );
+ return w;
+}
new file mode 100644
--- /dev/null
+++ b/gui//konsole_wcwidth.h
@@ -0,0 +1,24 @@
+/* $XFree86: xc/programs/xterm/wcwidth.h,v 1.2 2001/06/18 19:09:27 dickey Exp $ */
+
+/* Markus Kuhn -- 2001-01-12 -- public domain */
+/* Adaptions for KDE by Waldo Bastian <bastian@kde.org> */
+/*
+    Rewritten for QT4 by e_k <e_k at users.sourceforge.net>
+*/
+
+
+#ifndef	_KONSOLE_WCWIDTH_H_
+#define	_KONSOLE_WCWIDTH_H_
+
+// Qt
+#include <QtCore/QBool>
+#include <QtCore/QString>
+
+int konsole_wcwidth(quint16 ucs);
+#if 0
+int konsole_wcwidth_cjk(Q_UINT16 ucs);
+#endif
+
+int string_width( const QString &txt );
+
+#endif
new file mode 100644
--- /dev/null
+++ b/gui//kpty.cpp
@@ -0,0 +1,624 @@
+/*
+
+   This file is part of the KDE libraries
+   Copyright (C) 2002 Waldo Bastian <bastian@kde.org>
+   Copyright (C) 2002-2003,2007 Oswald Buddenhagen <ossi@kde.org>
+
+    Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public
+   License as published by the Free Software Foundation; either
+   version 2 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public License
+   along with this library; see the file COPYING.LIB.  If not, write to
+   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.
+*/
+
+#include "kpty_p.h"
+
+#ifdef __sgi
+#define __svr4__
+#endif
+
+#ifdef __osf__
+#define _OSF_SOURCE
+#include <float.h>
+#endif
+
+#ifdef _AIX
+#define _ALL_SOURCE
+#endif
+
+// __USE_XOPEN isn't defined by default in ICC
+// (needed for ptsname(), grantpt() and unlockpt())
+#ifdef __INTEL_COMPILER
+#  ifndef __USE_XOPEN
+#    define __USE_XOPEN
+#  endif
+#endif
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <time.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <grp.h>
+
+#if defined(HAVE_PTY_H)
+# include <pty.h>
+#endif
+
+#ifdef HAVE_LIBUTIL_H
+# include <libutil.h>
+#elif defined(HAVE_UTIL_H)
+# include <util.h>
+#endif
+
+#ifdef HAVE_UTEMPTER
+extern "C" {
+# include <utempter.h>
+}
+#else
+# include <utmp.h>
+# ifdef HAVE_UTMPX
+#  include <utmpx.h>
+# endif
+# if !defined(_PATH_UTMPX) && defined(_UTMPX_FILE)
+#  define _PATH_UTMPX _UTMPX_FILE
+# endif
+# if !defined(_PATH_WTMPX) && defined(_WTMPX_FILE)
+#  define _PATH_WTMPX _WTMPX_FILE
+# endif
+#endif
+
+/* for HP-UX (some versions) the extern C is needed, and for other
+   platforms it doesn't hurt */
+extern "C" {
+#include <termios.h>
+#if defined(HAVE_TERMIO_H)
+# include <termio.h> // struct winsize on some systems
+#endif
+}
+
+#if defined (_HPUX_SOURCE)
+# define _TERMIOS_INCLUDED
+# include <bsdtty.h>
+#endif
+
+#ifdef HAVE_SYS_STROPTS_H
+# include <sys/stropts.h>	// Defines I_PUSH
+# define _NEW_TTY_CTRL
+#endif
+
+#if defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) || defined (__bsdi__) || defined(__APPLE__) || defined (__DragonFly__)
+# define _tcgetattr(fd, ttmode) ioctl(fd, TIOCGETA, (char *)ttmode)
+#else
+# if defined(_HPUX_SOURCE) || defined(__Lynx__) || defined (__CYGWIN__)
+#  define _tcgetattr(fd, ttmode) tcgetattr(fd, ttmode)
+# else
+#  define _tcgetattr(fd, ttmode) ioctl(fd, TCGETS, (char *)ttmode)
+# endif
+#endif
+
+#if defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) || defined (__bsdi__) || defined(__APPLE__) || defined (__DragonFly__)
+# define _tcsetattr(fd, ttmode) ioctl(fd, TIOCSETA, (char *)ttmode)
+#else
+# if defined(_HPUX_SOURCE) || defined(__CYGWIN__)
+#  define _tcsetattr(fd, ttmode) tcsetattr(fd, TCSANOW, ttmode)
+# else
+#  define _tcsetattr(fd, ttmode) ioctl(fd, TCSETS, (char *)ttmode)
+# endif
+#endif
+
+//#include <kdebug.h>
+//#include <kstandarddirs.h>	// findExe
+
+#include <QtCore>
+
+// not defined on HP-UX for example
+#ifndef CTRL
+# define CTRL(x) ((x) & 037)
+#endif
+
+#define TTY_GROUP "tty"
+
+///////////////////////
+// private functions //
+///////////////////////
+
+//////////////////
+// private data //
+//////////////////
+
+KPtyPrivate::KPtyPrivate() :
+    masterFd(-1), slaveFd(-1)
+{
+}
+
+bool KPtyPrivate::chownpty(bool)
+{
+//    return !QProcess::execute(KStandardDirs::findExe("kgrantpty"),
+//        QStringList() << (grant?"--grant":"--revoke") << QString::number(masterFd));
+    return true;
+}
+
+/////////////////////////////
+// public member functions //
+/////////////////////////////
+
+KPty::KPty() :
+    d_ptr(new KPtyPrivate)
+{
+    d_ptr->q_ptr = this;
+}
+
+KPty::KPty(KPtyPrivate *d) :
+    d_ptr(d)
+{
+    d_ptr->q_ptr = this;
+}
+
+KPty::~KPty()
+{
+    close();
+    delete d_ptr;
+}
+
+bool KPty::open()
+{
+  Q_D(KPty);
+
+  if (d->masterFd >= 0)
+    return true;
+
+  QByteArray ptyName;
+
+  // Find a master pty that we can open ////////////////////////////////
+
+  // Because not all the pty animals are created equal, they want to
+  // be opened by several different methods.
+
+  // We try, as we know them, one by one.
+
+#ifdef HAVE_OPENPTY
+
+  char ptsn[PATH_MAX];
+  if (::openpty( &d->masterFd, &d->slaveFd, ptsn, 0, 0))
+  {
+    d->masterFd = -1;
+    d->slaveFd = -1;
+    kWarning(175) << "Can't open a pseudo teletype";
+    return false;
+  }
+  d->ttyName = ptsn;
+
+#else
+
+#ifdef HAVE__GETPTY // irix
+
+  char *ptsn = _getpty(&d->masterFd, O_RDWR|O_NOCTTY, S_IRUSR|S_IWUSR, 0);
+  if (ptsn) {
+    d->ttyName = ptsn;
+    goto grantedpt;
+  }
+
+#elif defined(HAVE_PTSNAME) || defined(TIOCGPTN)
+
+#ifdef HAVE_POSIX_OPENPT
+  d->masterFd = ::posix_openpt(O_RDWR|O_NOCTTY);
+#elif defined(HAVE_GETPT)
+  d->masterFd = ::getpt();
+#elif defined(PTM_DEVICE)
+  d->masterFd = ::open(PTM_DEVICE, O_RDWR|O_NOCTTY);
+#else
+# error No method to open a PTY master detected.
+#endif
+
+  if (d->masterFd >= 0)
+  {
+ 
+#ifdef HAVE_PTSNAME
+    char *ptsn = ptsname(d->masterFd);
+    if (ptsn) {
+        d->ttyName = ptsn;
+#else
+    int ptyno;
+    if (!ioctl(d->masterFd, TIOCGPTN, &ptyno)) {
+        d->ttyName = QByteArray("/dev/pts/") + QByteArray::number(ptyno);
+#endif
+#ifdef HAVE_GRANTPT
+        if (!grantpt(d->masterFd))
+           goto grantedpt;
+#else
+
+        goto gotpty;
+#endif
+    }
+    ::close(d->masterFd);
+    d->masterFd = -1;
+  }
+#endif // HAVE_PTSNAME || TIOCGPTN
+
+  // Linux device names, FIXME: Trouble on other systems?
+  for (const char* s3 = "pqrstuvwxyzabcde"; *s3; s3++)
+  {
+    for (const char* s4 = "0123456789abcdef"; *s4; s4++)
+    {
+      ptyName = QString().sprintf("/dev/pty%c%c", *s3, *s4).toAscii();
+      d->ttyName = QString().sprintf("/dev/tty%c%c", *s3, *s4).toAscii();
+
+      d->masterFd = ::open(ptyName.data(), O_RDWR);
+      if (d->masterFd >= 0)
+      {
+#ifdef Q_OS_SOLARIS
+        /* Need to check the process group of the pty.
+         * If it exists, then the slave pty is in use,
+         * and we need to get another one.
+         */
+        int pgrp_rtn;
+        if (ioctl(d->masterFd, TIOCGPGRP, &pgrp_rtn) == 0 || errno != EIO) {
+          ::close(d->masterFd);
+          d->masterFd = -1;
+          continue;
+        }
+#endif /* Q_OS_SOLARIS */
+        if (!access(d->ttyName.data(),R_OK|W_OK)) // checks availability based on permission bits
+        {
+          if (!geteuid())
+          {
+            struct group* p = getgrnam(TTY_GROUP);
+            if (!p)
+              p = getgrnam("wheel");
+            gid_t gid = p ? p->gr_gid : getgid ();
+
+            chown(d->ttyName.data(), getuid(), gid);
+            chmod(d->ttyName.data(), S_IRUSR|S_IWUSR|S_IWGRP);
+          }
+          goto gotpty;
+        }
+        ::close(d->masterFd);
+        d->masterFd = -1;
+      }
+    }
+  }
+
+  qWarning() << "Can't open a pseudo teletype";
+  return false;
+
+ gotpty:
+  struct stat st;
+  if (stat(d->ttyName.data(), &st)) {
+    return false; // this just cannot happen ... *cough*  Yeah right, I just
+                  // had it happen when pty #349 was allocated.  I guess
+                  // there was some sort of leak?  I only had a few open.
+    }
+  if (((st.st_uid != getuid()) ||
+       (st.st_mode & (S_IRGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH))) &&
+      !d->chownpty(true))
+  {
+    qWarning()
+      << "chownpty failed for device " << ptyName << "::" << d->ttyName
+      << "\nThis means the communication can be eavesdropped." << endl;
+  }
+
+#if defined (HAVE__GETPTY) || defined (HAVE_GRANTPT)
+ grantedpt:
+#endif 
+
+#ifdef HAVE_REVOKE
+  revoke(d->ttyName.data());
+#endif
+
+#ifdef HAVE_UNLOCKPT
+  unlockpt(d->masterFd);
+#elif defined(TIOCSPTLCK)
+  int flag = 0;
+  ioctl(d->masterFd, TIOCSPTLCK, &flag);
+#endif
+
+  d->slaveFd = ::open(d->ttyName.data(), O_RDWR | O_NOCTTY);
+  if (d->slaveFd < 0)
+  {
+    qWarning() << "Can't open slave pseudo teletype";
+    ::close(d->masterFd);
+    d->masterFd = -1;
+    return false;
+  }
+
+#if (defined(__svr4__) || defined(__sgi__))
+  // Solaris
+  ioctl(d->slaveFd, I_PUSH, "ptem");
+  ioctl(d->slaveFd, I_PUSH, "ldterm");
+#endif
+
+#endif /* HAVE_OPENPTY */
+
+  fcntl(d->masterFd, F_SETFD, FD_CLOEXEC);
+  fcntl(d->slaveFd, F_SETFD, FD_CLOEXEC);
+
+  return true;
+}
+
+void KPty::closeSlave()
+{
+    Q_D(KPty);
+
+    if (d->slaveFd < 0)
+        return;
+    ::close(d->slaveFd);
+    d->slaveFd = -1;
+}
+
+void KPty::close()
+{
+   Q_D(KPty);
+
+   if (d->masterFd < 0)
+      return;
+   closeSlave();
+   // don't bother resetting unix98 pty, it will go away after closing master anyway.
+   if (memcmp(d->ttyName.data(), "/dev/pts/", 9)) {
+      if (!geteuid()) {
+         struct stat st;
+         if (!stat(d->ttyName.data(), &st)) {
+            chown(d->ttyName.data(), 0, st.st_gid == getgid() ? 0 : -1);
+            chmod(d->ttyName.data(), S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
+         }
+      } else {
+         fcntl(d->masterFd, F_SETFD, 0);
+         d->chownpty(false);
+      }
+   }
+   ::close(d->masterFd);
+   d->masterFd = -1;
+}
+
+void KPty::setCTty()
+{
+    Q_D(KPty);
+
+    // Setup job control //////////////////////////////////
+
+    // Become session leader, process group leader,
+    // and get rid of the old controlling terminal.
+    setsid();
+
+    // make our slave pty the new controlling terminal.
+#ifdef TIOCSCTTY
+    ioctl(d->slaveFd, TIOCSCTTY, 0);
+#else
+    // __svr4__ hack: the first tty opened after setsid() becomes controlling tty
+    ::close(::open(d->ttyName, O_WRONLY, 0));
+#endif
+
+    // make our new process group the foreground group on the pty
+    int pgrp = getpid();
+#if defined(_POSIX_VERSION) || defined(__svr4__)
+    tcsetpgrp(d->slaveFd, pgrp);
+#elif defined(TIOCSPGRP)
+    ioctl(d->slaveFd, TIOCSPGRP, (char *)&pgrp);
+#endif
+}
+
+void KPty::login(const char *user, const char *remotehost)
+{
+#ifdef HAVE_UTEMPTER
+    Q_D(KPty);
+
+    addToUtmp(d->ttyName, remotehost, d->masterFd);
+    Q_UNUSED(user);
+#else
+# ifdef HAVE_UTMPX
+    struct utmpx l_struct;
+# else
+    struct utmp l_struct;
+# endif
+    memset(&l_struct, 0, sizeof(l_struct));
+    // note: strncpy without terminators _is_ correct here. man 4 utmp
+
+    if (user)
+      strncpy(l_struct.ut_name, user, sizeof(l_struct.ut_name));
+
+    if (remotehost) {
+      strncpy(l_struct.ut_host, remotehost, sizeof(l_struct.ut_host));
+# ifdef HAVE_STRUCT_UTMP_UT_SYSLEN
+      l_struct.ut_syslen = qMin(strlen(remotehost), sizeof(l_struct.ut_host));
+# endif
+    }
+
+# ifndef __GLIBC__
+    Q_D(KPty);
+    const char *str_ptr = d->ttyName.data();
+    if (!memcmp(str_ptr, "/dev/", 5))
+        str_ptr += 5;
+    strncpy(l_struct.ut_line, str_ptr, sizeof(l_struct.ut_line));
+#  ifdef HAVE_STRUCT_UTMP_UT_ID
+    strncpy(l_struct.ut_id,
+            str_ptr + strlen(str_ptr) - sizeof(l_struct.ut_id),
+            sizeof(l_struct.ut_id));
+#  endif
+# endif
+
+# ifdef HAVE_UTMPX
+    gettimeofday(&l_struct.ut_tv, 0);
+# else
+    l_struct.ut_time = time(0);
+# endif
+
+# ifdef HAVE_LOGIN
+#  ifdef HAVE_LOGINX
+    ::loginx(&l_struct);
+#  else
+    ::login(&l_struct);
+#  endif
+# else
+#  ifdef HAVE_STRUCT_UTMP_UT_TYPE
+    l_struct.ut_type = USER_PROCESS;
+#  endif
+#  ifdef HAVE_STRUCT_UTMP_UT_PID
+    l_struct.ut_pid = getpid();
+#   ifdef HAVE_STRUCT_UTMP_UT_SESSION
+    l_struct.ut_session = getsid(0);
+#   endif
+#  endif
+#  ifdef HAVE_UTMPX
+    utmpxname(_PATH_UTMPX);
+    setutxent();
+    pututxline(&l_struct);
+    endutxent();
+    updwtmpx(_PATH_WTMPX, &l_struct);
+#  else
+    utmpname(_PATH_UTMP);
+    setutent();
+    pututline(&l_struct);
+    endutent();
+    updwtmp(_PATH_WTMP, &l_struct);
+#  endif
+# endif
+#endif
+}
+
+void KPty::logout()
+{
+#ifdef HAVE_UTEMPTER
+    Q_D(KPty);
+
+    removeLineFromUtmp(d->ttyName, d->masterFd);
+#else
+    Q_D(KPty);
+
+    const char *str_ptr = d->ttyName.data();
+    if (!memcmp(str_ptr, "/dev/", 5))
+        str_ptr += 5;
+# ifdef __GLIBC__
+    else {
+        const char *sl_ptr = strrchr(str_ptr, '/');
+        if (sl_ptr)
+            str_ptr = sl_ptr + 1;
+    }
+# endif
+# ifdef HAVE_LOGIN
+#  ifdef HAVE_LOGINX
+    ::logoutx(str_ptr, 0, DEAD_PROCESS);
+#  else
+    ::logout(str_ptr);
+#  endif
+# else
+#  ifdef HAVE_UTMPX
+    struct utmpx l_struct, *ut;
+#  else
+    struct utmp l_struct, *ut;
+#  endif
+    memset(&l_struct, 0, sizeof(l_struct));
+
+    strncpy(l_struct.ut_line, str_ptr, sizeof(l_struct.ut_line));
+
+#  ifdef HAVE_UTMPX
+    utmpxname(_PATH_UTMPX);
+    setutxent();
+    if ((ut = getutxline(&l_struct))) {
+#  else
+    utmpname(_PATH_UTMP);
+    setutent();
+    if ((ut = getutline(&l_struct))) {
+#  endif
+        memset(ut->ut_name, 0, sizeof(*ut->ut_name));
+        memset(ut->ut_host, 0, sizeof(*ut->ut_host));
+#  ifdef HAVE_STRUCT_UTMP_UT_SYSLEN
+        ut->ut_syslen = 0;
+#  endif
+#  ifdef HAVE_STRUCT_UTMP_UT_TYPE
+        ut->ut_type = DEAD_PROCESS;
+#  endif
+#  ifdef HAVE_UTMPX
+        gettimeofday(ut->ut_tv, 0);
+        pututxline(ut);
+    }
+    endutxent();
+#  else
+        ut->ut_time = time(0);
+        pututline(ut);
+    }
+    endutent();
+#  endif
+# endif
+#endif
+}
+
+// XXX Supposedly, tc[gs]etattr do not work with the master on Solaris.
+// Please verify.
+
+bool KPty::tcGetAttr(struct ::termios *ttmode) const
+{
+    Q_D(const KPty);
+
+    return _tcgetattr(d->masterFd, ttmode) == 0;
+}
+
+bool KPty::tcSetAttr(struct ::termios *ttmode)
+{
+    Q_D(KPty);
+
+    return _tcsetattr(d->masterFd, ttmode) == 0;
+}
+
+bool KPty::setWinSize(int lines, int columns)
+{
+    Q_D(KPty);
+
+    struct winsize winSize;
+    memset(&winSize, 0, sizeof(winSize));
+    winSize.ws_row = (unsigned short)lines;
+    winSize.ws_col = (unsigned short)columns;
+    return ioctl(d->masterFd, TIOCSWINSZ, (char *)&winSize) == 0;
+}
+
+bool KPty::setEcho(bool echo)
+{
+    struct ::termios ttmode;
+    if (!tcGetAttr(&ttmode))
+        return false;
+    if (!echo)
+        ttmode.c_lflag &= ~ECHO;
+    else
+        ttmode.c_lflag |= ECHO;
+    return tcSetAttr(&ttmode);
+}
+
+const char *KPty::ttyName() const
+{
+    Q_D(const KPty);
+
+    return d->ttyName.data();
+}
+
+int KPty::masterFd() const
+{
+    Q_D(const KPty);
+
+    return d->masterFd;
+}
+
+int KPty::slaveFd() const
+{
+    Q_D(const KPty);
+
+    return d->slaveFd;
+}
new file mode 100644
--- /dev/null
+++ b/gui//kpty.h
@@ -0,0 +1,188 @@
+/* This file is part of the KDE libraries
+
+    Copyright (C) 2003,2007 Oswald Buddenhagen <ossi@kde.org>
+
+    Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public License
+    along with this library; see the file COPYING.LIB.  If not, write to
+    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+    Boston, MA 02110-1301, USA.
+*/
+
+#ifndef kpty_h
+#define kpty_h
+
+#include <QtCore>
+
+struct KPtyPrivate;
+struct termios;
+
+/**
+ * Provides primitives for opening & closing a pseudo TTY pair, assigning the
+ * controlling TTY, utmp registration and setting various terminal attributes.
+ */
+class KPty {
+    Q_DECLARE_PRIVATE(KPty)
+
+public:
+
+  /**
+   * Constructor
+   */
+  KPty();
+
+  /**
+   * Destructor:
+   *
+   *  If the pty is still open, it will be closed. Note, however, that
+   *  an utmp registration is @em not undone.
+  */
+  ~KPty();
+
+  /**
+   * Create a pty master/slave pair.
+   *
+   * @return true if a pty pair was successfully opened
+   */
+  bool open();
+
+  /**
+   * Close the pty master/slave pair.
+   */
+  void close();
+
+  /**
+   * Close the pty slave descriptor.
+   *
+   * When creating the pty, KPty also opens the slave and keeps it open.
+   * Consequently the master will never receive an EOF notification.
+   * Usually this is the desired behavior, as a closed pty slave can be
+   * reopened any time - unlike a pipe or socket. However, in some cases
+   * pipe-alike behavior might be desired.
+   *
+   * After this function was called, slaveFd() and setCTty() cannot be
+   * used.
+   */
+  void closeSlave();
+
+  /**
+   * Creates a new session and process group and makes this pty the
+   * controlling tty.
+   */
+  void setCTty();
+
+  /**
+   * Creates an utmp entry for the tty.
+   * This function must be called after calling setCTty and
+   * making this pty the stdin.
+   * @param user the user to be logged on
+   * @param remotehost the host from which the login is coming. This is
+   *  @em not the local host. For remote logins it should be the hostname
+   *  of the client. For local logins from inside an X session it should
+   *  be the name of the X display. Otherwise it should be empty.
+   */
+  void login(const char *user = 0, const char *remotehost = 0);
+
+  /**
+   * Removes the utmp entry for this tty.
+   */
+  void logout();
+
+  /**
+   * Wrapper around tcgetattr(3).
+   *
+   * This function can be used only while the PTY is open.
+   * You will need an #include &lt;termios.h&gt; to do anything useful
+   * with it.
+   *
+   * @param ttmode a pointer to a termios structure.
+   *  Note: when declaring ttmode, @c struct @c ::termios must be used -
+   *  without the '::' some version of HP-UX thinks, this declares
+   *  the struct in your class, in your method.
+   * @return @c true on success, false otherwise
+   */
+  bool tcGetAttr(struct ::termios *ttmode) const;
+
+  /**
+   * Wrapper around tcsetattr(3) with mode TCSANOW.
+   *
+   * This function can be used only while the PTY is open.
+   *
+   * @param ttmode a pointer to a termios structure.
+   * @return @c true on success, false otherwise. Note that success means
+   *  that @em at @em least @em one attribute could be set.
+   */
+  bool tcSetAttr(struct ::termios *ttmode);
+
+  /**
+   * Change the logical (screen) size of the pty.
+   * The default is 24 lines by 80 columns.
+   *
+   * This function can be used only while the PTY is open.
+   *
+   * @param lines the number of rows
+   * @param columns the number of columns
+   * @return @c true on success, false otherwise
+   */
+  bool setWinSize(int lines, int columns);
+
+  /**
+   * Set whether the pty should echo input.
+   *
+   * Echo is on by default.
+   * If the output of automatically fed (non-interactive) PTY clients
+   * needs to be parsed, disabling echo often makes it much simpler.
+   *
+   * This function can be used only while the PTY is open.
+   *
+   * @param echo true if input should be echoed.
+   * @return @c true on success, false otherwise
+   */
+  bool setEcho(bool echo);
+
+  /**
+   * @return the name of the slave pty device.
+   *
+   * This function should be called only while the pty is open.
+   */
+  const char *ttyName() const;
+
+  /**
+   * @return the file descriptor of the master pty
+   *
+   * This function should be called only while the pty is open.
+   */
+  int masterFd() const;
+
+  /**
+   * @return the file descriptor of the slave pty
+   *
+   * This function should be called only while the pty slave is open.
+   */
+  int slaveFd() const;
+
+protected:
+  /**
+   * @internal
+   */
+  KPty(KPtyPrivate *d);
+
+  /**
+   * @internal
+   */
+  KPtyPrivate * const d_ptr;
+};
+
+#endif
+
new file mode 100644
--- /dev/null
+++ b/gui//kpty_p.h
@@ -0,0 +1,44 @@
+/* This file is part of the KDE libraries
+
+    Copyright (C) 2003,2007 Oswald Buddenhagen <ossi@kde.org>
+
+    Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public License
+    along with this library; see the file COPYING.LIB.  If not, write to
+    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+    Boston, MA 02110-1301, USA.
+*/
+
+#ifndef kpty_p_h
+#define kpty_p_h
+
+#include "kpty.h"
+
+#include <QtCore/QByteArray>
+
+struct KPtyPrivate {
+    Q_DECLARE_PUBLIC(KPty)
+
+    KPtyPrivate();
+    bool chownpty(bool grant);
+
+    int masterFd;
+    int slaveFd;
+
+    QByteArray ttyName;
+
+    KPty *q_ptr;
+};
+
+#endif
new file mode 100644
--- /dev/null
+++ b/gui//lib.pro
@@ -0,0 +1,48 @@
+TEMPLATE	= lib
+VERSION		= 0.1.0
+DESTDIR 	= ..
+
+TARGET		= qtermwidget
+
+CONFIG		+= qt debug_and_release warn_on build_all staticlib #dll
+
+QT += core gui
+
+MOC_DIR 	= ../.moc
+
+CONFIG(debug, debug|release) {
+    OBJECTS_DIR = ../.objs_d
+    TARGET 	= qtermwidget_d
+} else {
+    OBJECTS_DIR = ../.objs
+    TARGET 	= qtermwidget
+}
+
+DEFINES 	+= HAVE_POSIX_OPENPT	    
+#or DEFINES 	+= HAVE_GETPT
+
+HEADERS 	= TerminalCharacterDecoder.h Character.h CharacterColor.h \
+		KeyboardTranslator.h \
+		ExtendedDefaultTranslator.h \
+		Screen.h History.h BlockArray.h konsole_wcwidth.h \
+		ScreenWindow.h \
+		Emulation.h \
+		Vt102Emulation.h TerminalDisplay.h Filter.h LineFont.h \
+		Pty.h kpty.h kpty_p.h k3process.h k3processcontroller.h \
+		Session.h ShellCommand.h \
+		qtermwidget.h
+
+SOURCES 	= TerminalCharacterDecoder.cpp \
+		KeyboardTranslator.cpp \
+		Screen.cpp History.cpp BlockArray.cpp konsole_wcwidth.cpp \
+		ScreenWindow.cpp \
+		Emulation.cpp \
+		Vt102Emulation.cpp TerminalDisplay.cpp Filter.cpp \
+		Pty.cpp kpty.cpp k3process.cpp k3processcontroller.cpp \
+		Session.cpp ShellCommand.cpp \
+		qtermwidget.cpp
+
+	    
+
+
+	
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/gui//qtermwidget.cpp
@@ -0,0 +1,222 @@
+/*  Copyright (C) 2008 e_k (e_k@users.sourceforge.net)
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+		
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Library General Public License for more details.
+				
+    You should have received a copy of the GNU Library General Public License
+    along with this library; see the file COPYING.LIB.  If not, write to
+    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+    Boston, MA 02110-1301, USA.
+*/
+						
+
+#include "qtermwidget.h"
+
+#include "Session.h"
+#include "TerminalDisplay.h"
+
+using namespace Konsole;
+
+void *createTermWidget(int startnow, void *parent)
+{ 
+    return (void*) new QTermWidget(startnow, (QWidget*)parent); 
+}
+
+struct TermWidgetImpl
+{
+    TermWidgetImpl(QWidget* parent = 0);
+
+    TerminalDisplay *m_terminalDisplay;
+    Session *m_session;
+    
+    Session* createSession();
+    TerminalDisplay* createTerminalDisplay(Session *session, QWidget* parent);
+};
+
+TermWidgetImpl::TermWidgetImpl(QWidget* parent)
+{
+    this->m_session = createSession();
+    this->m_terminalDisplay = createTerminalDisplay(this->m_session, parent);
+}
+
+
+Session *TermWidgetImpl::createSession()
+{
+    Session *session = new Session();
+
+    session->setTitle(Session::NameRole, "QTermWidget");
+    session->setProgram("/bin/bash");
+    QStringList args("");
+    session->setArguments(args);
+    session->setAutoClose(true);
+		    
+    session->setCodec(QTextCodec::codecForName("UTF-8"));
+			
+    session->setFlowControlEnabled(true);
+    session->setHistoryType(HistoryTypeBuffer(1000));
+    
+    session->setDarkBackground(true);
+	    
+    session->setKeyBindings("");	    
+    return session;
+}
+
+TerminalDisplay *TermWidgetImpl::createTerminalDisplay(Session *session, QWidget* parent)
+{
+//    TerminalDisplay* display = new TerminalDisplay(this);
+    TerminalDisplay* display = new TerminalDisplay(parent);
+    
+    display->setBellMode(TerminalDisplay::NotifyBell);
+    display->setTerminalSizeHint(true);
+    display->setTripleClickMode(TerminalDisplay::SelectWholeLine);
+    display->setTerminalSizeStartup(true);
+
+    display->setRandomSeed(session->sessionId() * 31);
+    
+    return display;
+}
+
+
+QTermWidget::QTermWidget(int startnow, QWidget *parent)
+:QWidget(parent)
+{
+    m_impl = new TermWidgetImpl(this);
+    
+    init();
+
+    if (startnow && m_impl->m_session) {
+	m_impl->m_session->run();
+    }
+    
+    this->setFocus( Qt::OtherFocusReason );
+    m_impl->m_terminalDisplay->resize(this->size());
+    
+    this->setFocusProxy(m_impl->m_terminalDisplay);
+}
+
+void QTermWidget::startShellProgram()
+{
+    if ( m_impl->m_session->isRunning() )
+	return;
+	
+    m_impl->m_session->run();
+}
+
+void QTermWidget::init()
+{    
+    m_impl->m_terminalDisplay->setSize(80, 40);
+    
+    QFont font = QApplication::font(); 
+    font.setFamily("Monospace");
+    font.setPointSize(10);
+    font.setStyleHint(QFont::TypeWriter);
+    setTerminalFont(font);
+    setScrollBarPosition(NoScrollBar);    
+        
+    m_impl->m_session->addView(m_impl->m_terminalDisplay);
+    
+    connect(m_impl->m_session, SIGNAL(finished()), this, SLOT(sessionFinished()));
+}
+
+
+QTermWidget::~QTermWidget()
+{
+    emit destroyed();
+}
+
+
+void QTermWidget::setTerminalFont(QFont &font)
+{
+    if (!m_impl->m_terminalDisplay)
+	return;
+    m_impl->m_terminalDisplay->setVTFont(font);
+}
+
+void QTermWidget::setShellProgram(QString &progname)
+{
+    if (!m_impl->m_session)
+	return;
+    m_impl->m_session->setProgram(progname);	
+}
+
+void QTermWidget::setArgs(QStringList &args)
+{
+    if (!m_impl->m_session)
+	return;
+    m_impl->m_session->setArguments(args);	
+}
+
+void QTermWidget::setTextCodec(QTextCodec *codec)
+{
+    if (!m_impl->m_session)
+	return;
+    m_impl->m_session->setCodec(codec);	
+}
+
+void QTermWidget::setColorScheme(int scheme)
+{
+    switch(scheme) {
+	case COLOR_SCHEME_WHITE_ON_BLACK:
+		m_impl->m_terminalDisplay->setColorTable(whiteonblack_color_table);
+		break;		
+	case COLOR_SCHEME_GREEN_ON_BLACK:
+		m_impl->m_terminalDisplay->setColorTable(greenonblack_color_table);
+		break;
+	case COLOR_SCHEME_BLACK_ON_LIGHT_YELLOW:
+		m_impl->m_terminalDisplay->setColorTable(blackonlightyellow_color_table);
+		break;
+	default: //do nothing
+	    break;
+    };
+}
+
+void QTermWidget::setSize(int h, int v)
+{
+    if (!m_impl->m_terminalDisplay)
+	return;
+    m_impl->m_terminalDisplay->setSize(h, v);
+}
+
+void QTermWidget::setHistorySize(int lines)
+{
+    if (lines < 0)
+        m_impl->m_session->setHistoryType(HistoryTypeFile());
+    else
+	m_impl->m_session->setHistoryType(HistoryTypeBuffer(lines));
+}
+
+void QTermWidget::setScrollBarPosition(ScrollBarPosition pos)
+{
+    if (!m_impl->m_terminalDisplay)
+	return;
+    m_impl->m_terminalDisplay->setScrollBarPosition((TerminalDisplay::ScrollBarPosition)pos);
+}
+
+void QTermWidget::sendText(QString &text)
+{
+    m_impl->m_session->sendText(text); 
+}
+
+void QTermWidget::resizeEvent(QResizeEvent*)
+{
+//qDebug("global window resizing...with %d %d", this->size().width(), this->size().height());
+    m_impl->m_terminalDisplay->resize(this->size());
+}
+
+
+
+void QTermWidget::sessionFinished()
+{
+    emit finished();
+}
+
+	
+//#include "moc_consoleq.cpp"
+
new file mode 100644
--- /dev/null
+++ b/gui//qtermwidget.h
@@ -0,0 +1,108 @@
+/*  Copyright (C) 2008 e_k (e_k@users.sourceforge.net)
+    
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+		    
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Library General Public License for more details.
+			    
+    You should have received a copy of the GNU Library General Public License
+    along with this library; see the file COPYING.LIB.  If not, write to
+    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+    Boston, MA 02110-1301, USA.
+*/
+						    
+
+#ifndef _Q_TERM_WIDGET
+#define _Q_TERM_WIDGET
+
+#include <QtGui>
+
+struct TermWidgetImpl;
+
+enum COLOR_SCHEME {     COLOR_SCHEME_WHITE_ON_BLACK	= 1,
+		        COLOR_SCHEME_GREEN_ON_BLACK,
+		        COLOR_SCHEME_BLACK_ON_LIGHT_YELLOW };
+
+class QTermWidget : public QWidget
+{
+    Q_OBJECT
+public:
+    
+    enum ScrollBarPosition
+    {
+        /** Do not show the scroll bar. */
+        NoScrollBar=0,
+        /** Show the scroll bar on the left side of the display. */
+        ScrollBarLeft=1,
+        /** Show the scroll bar on the right side of the display. */
+        ScrollBarRight=2
+    };
+
+
+    //Creation of widget
+    QTermWidget(int startnow = 1, //start shell programm immediatelly
+		QWidget *parent = 0);
+    ~QTermWidget();
+
+    //start shell program if it was not started in constructor
+    void startShellProgram();
+    
+    //look-n-feel, if you don`t like defaults
+
+    //	Terminal font
+    // Default is application font with family Monospace, size 10
+    void setTerminalFont(QFont &font); 
+    
+    //	Shell program, default is /bin/bash
+    void setShellProgram(QString &progname);
+    
+    // Shell program args, default is none
+    void setArgs(QStringList &args);
+    
+    //Text codec, default is UTF-8
+    void setTextCodec(QTextCodec *codec);
+
+    //Color scheme, default is white on black
+    void setColorScheme(int scheme);
+    
+    //set size
+    void setSize(int h, int v);
+    
+    // History size for scrolling 
+    void setHistorySize(int lines); //infinite if lines < 0
+
+    // Presence of scrollbar
+    void setScrollBarPosition(ScrollBarPosition);
+    
+    // Send some text to terminal
+    void sendText(QString &text);
+            
+signals:
+    void finished();
+        
+protected: 
+    virtual void resizeEvent(QResizeEvent *);
+    
+protected slots:
+    void sessionFinished();        
+    
+private:
+    void init();    
+    TermWidgetImpl *m_impl;
+};
+
+
+//Maybe useful, maybe not
+
+#ifdef __cplusplus
+extern "C"
+#endif
+void *createTermWidget(int startnow, void *parent); 
+
+#endif
+