changeset 13497:d30d5adafdb1

Merge with Savannah
author Jordi Gutiérrez Hermoso <jordigh@gmail.com>
date Thu, 02 Jun 2011 23:09:36 -0500
parents 53c0ed961de8 (current diff) a1694c79f9c1 (diff)
children e05d6d17196e
files
diffstat 176 files changed, 52947 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//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//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//Quint.pro
@@ -0,0 +1,113 @@
+# Quint - A graphical user interface for Octave
+# Copyright (C) 2011 Jacob Dawid
+# jacob.dawid@googlemail.com
+#
+# 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 3 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, see <http://www.gnu.org/licenses/>.
+
+
+# Basic settings:
+QT                  += core gui webkit xml opengl   # Qt modules
+TEMPLATE            = app                           # Build as application
+TARGET              = Quint                         # Name of the target binary
+
+DESTDIR             = bin                           # Destination of the output
+UI_DIR              = ui-files                      # Folder for ui files
+MOC_DIR             = moc-files                     # Folder for moc files
+OBJECTS_DIR         = object-files                  # Folder for object files
+
+TRANSLATIONS        += languages/german             # Available translations
+
+# Includepaths and libraries to link against:
+INCLUDEPATH         += src
+INCFLAGS            += $$system(mkoctfile -p INCFLAGS)
+LFLAGS              += $$system(mkoctfile -p LFLAGS) \
+                       $$system(mkoctfile -p OCTAVE_LIBS) \
+                       $$system(mkoctfile -p LIBS)
+QMAKE_LFLAGS        += $$LFLAGS -lutil $$system(mkoctfile -p RLD_FLAG)
+QMAKE_CXXFLAGS      += $$INCFLAGS
+
+# Files associated with the project:
+SOURCES +=\
+        src/TerminalCharacterDecoder.cpp \
+        src/KeyboardTranslator.cpp \
+        src/Screen.cpp \
+        src/History.cpp \
+        src/BlockArray.cpp \
+        src/konsole_wcwidth.cpp \
+        src/ScreenWindow.cpp \
+        src/Emulation.cpp \
+        src/Vt102Emulation.cpp \
+        src/TerminalDisplay.cpp \
+        src/Filter.cpp \
+        src/Pty.cpp \
+        src/kpty.cpp \
+        src/kptyprocess.cpp \
+        src/kprocess.cpp \
+        src/kptydevice.cpp \
+        src/Session.cpp \
+        src/ShellCommand.cpp \
+        src/QTerminalWidget.cpp \
+        src/MainWindow.cpp \
+        src/Quint.cpp \
+        src/OctaveLink.cpp \
+        src/ProcessInfo.cpp \
+    src/OctaveTerminal.cpp \
+    src/VariablesDockWidget.cpp \
+    src/HistoryDockWidget.cpp \
+    src/FilesDockWidget.cpp \
+    src/FileEditorDockWidget.cpp \
+    src/SyntaxHighlighter.cpp \
+    src/BrowserWidget.cpp \
+    src/NumberedCodeEdit.cpp \
+    src/SimpleEditor.cpp \
+    src/ImageViewerDockWidget.cpp
+
+HEADERS += \
+        src/TerminalCharacterDecoder.h \
+        src/Character.h \
+        src/CharacterColor.h \
+        src/KeyboardTranslator.h \
+        src/Screen.h \
+        src/History.h \
+        src/BlockArray.h \
+        src/konsole_wcwidth.h \
+        src/ScreenWindow.h \
+        src/Emulation.h \
+        src/Vt102Emulation.h \
+        src/TerminalDisplay.h \
+        src/Filter.h \
+        src/LineFont.h \
+        src/Pty.h \
+        src/kpty.h \
+        src/kpty_p.h \
+        src/kptyprocess.h \
+        src/kprocess.h \
+        src/kprocess_p.h \
+        src/kptydevice.h \
+        src/Session.h \
+        src/ShellCommand.h \
+        src/QTerminalWidget.h \
+    	src/MainWindow.h \
+        src/OctaveLink.h \
+        src/ProcessInfo.h \
+    src/OctaveTerminal.h \
+    src/VariablesDockWidget.h \
+    src/HistoryDockWidget.h \
+    src/FilesDockWidget.h \
+    src/FileEditorDockWidget.h \
+    src/SyntaxHighlighter.h \
+    src/BrowserWidget.h \
+    src/NumberedCodeEdit.h \
+    src/SimpleEditor.h \
+    src/ImageViewerDockWidget.h
new file mode 100644
--- /dev/null
+++ b/gui//README
@@ -0,0 +1,46 @@
+Quint is using the QTermWidget to emulate a terminal, this enabling readline support for Octave. This is the original README file from the author:
+
+###########################################################################################
+QTermWidget
+version 0.1.0
+
+QTermWidget is an opensource project based on KDE4 Konsole application.
+The main goal of this project is to provide unicode-enabled, embeddable
+QT widget for using as a built-in console (or terminal emulation widget).
+
+Of course I`m aware about embedding abilities of original Konsole,
+but once I had Qt without KDE, and it was a serious obstacle.
+I decided not to rely on a chance. I cannot find any interesting related project,
+so I had to write it.
+
+The original Konsole`s code was rewritten entirely with QT4 only; also I have to
+include in the project some parts of code from kde core library. All code dealing
+with user interface parts and session managers was removed (maybe later I bring it
+back somehow), and the result is quite useful, I suppose.
+
+This library was compiled and tested on three linux systems,
+based on 2.4.32, 2.6.20, 2.6.23 kernels, x86 and amd64.
+Please inform about its behaviour on other systems.
+###########################################################################################
+
+If you cannot launch Quint because it fails to find octave's shared libraries and you are sure that you have them installed, you will need
+to do an
+
+export LD_LIBRARY_PATH=/usr/lib/octave-x.x.x/:$LD_LIBRARY_PATH && bin/Quint
+
+and replace x.x.x by the specific octave version you have installed to run Quint. If you don't want to do that each time you launch Quint,
+do the following:
+
+sudo gedit /etc/ld.so.conf 
+
+and append the line:
+
+/usr/lib/octave-x.x.x/
+
+Save the file and do:
+
+sudo ldconfig
+
+Now Quint should not complain about missing shared libraries. If you have any problems, suggestions or ideas, feel free to drop me a mail at
+jacob.dawid@googlemail.com - Jacob Dawid
+
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
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//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
new file mode 100644
--- /dev/null
+++ b/gui//src/BlockArray.cpp
@@ -0,0 +1,332 @@
+/*
+    This file is part of Konsole, an X terminal.
+    Copyright 2000 by Stephan Kulow <coolo@kde.org>
+
+    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"
+
+// System
+#include <assert.h>
+#include <sys/mman.h>
+#include <sys/param.h>
+#include <unistd.h>
+#include <stdio.h>
+
+#define KDE_fseek ::fseek
+#define KDE_lseek ::lseek
+
+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 = KDE_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) {
+        //kDebug(1211) << "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);
+        if (ftruncate(ion, length*blocksize) == -1)
+            perror("ftruncate");
+        size = newsize;
+
+        return true;
+    }
+}
+
+void moveBlock(FILE *fion, int cursor, int newpos, char *buffer2)
+{
+    int res = KDE_fseek(fion, cursor * blocksize, SEEK_SET);
+    if (res)
+        perror("fseek");
+    res = fread(buffer2, blocksize, 1, fion);
+    if (res != 1)
+        perror("fread");
+
+    res = KDE_fseek(fion, newpos * blocksize, SEEK_SET);
+    if (res)
+        perror("fseek");
+    res = fwrite(buffer2, blocksize, 1, fion);
+    if (res != 1)
+        perror("fwrite");
+}
+
+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 = KDE_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 = KDE_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//src/BlockArray.h
@@ -0,0 +1,115 @@
+/*
+    This file is part of Konsole, an X terminal.
+    Copyright 2000 by Stephan Kulow <coolo@kde.org>
+
+    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>
+
+#define BlockSize (1 << 12)
+#define ENTRIES   ((BlockSize - sizeof(size_t) ) / sizeof(unsigned char))
+
+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 transferred.
+    * 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//src/BrowserWidget.cpp
@@ -0,0 +1,90 @@
+/* Quint - A graphical user interface for Octave
+ * Copyright (C) 2011 Jacob Dawid
+ * jacob.dawid@googlemail.com
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "BrowserWidget.h"
+#include <QVBoxLayout>
+#include <QAction>
+#include <QStyle>
+#include <QApplication>
+
+BrowserDockWidget::BrowserDockWidget(QWidget *parent, BrowserWidget *browserWidget)
+    : QDockWidget(parent) {
+    m_browserWidget = browserWidget;
+    setWidget(m_browserWidget);
+}
+
+BrowserDockWidget::~BrowserDockWidget() {
+}
+
+BrowserWidget *BrowserDockWidget::browserWidget() {
+    return m_browserWidget;
+}
+
+BrowserWidget::BrowserWidget(QWidget *parent)
+    : QWidget(parent) {
+    construct();
+}
+
+void BrowserWidget::construct() {
+    QStyle *style = QApplication::style();
+    m_navigationToolBar = new QToolBar(this);
+    m_webView = new QWebView(this);
+    m_urlLineEdit = new QLineEdit(this);
+    m_statusBar = new QStatusBar(this);
+
+    QAction *backAction = new QAction(style->standardIcon(QStyle::SP_ArrowLeft),
+        "", m_navigationToolBar);
+    QAction *forwardAction = new QAction(style->standardIcon(QStyle::SP_ArrowRight),
+        "", m_navigationToolBar);
+
+    m_navigationToolBar->addAction(backAction);
+    m_navigationToolBar->addAction(forwardAction);
+    m_navigationToolBar->addWidget(m_urlLineEdit);
+
+    QVBoxLayout *layout = new QVBoxLayout();
+    layout->addWidget(m_navigationToolBar);
+    layout->addWidget(m_webView);
+    layout->addWidget(m_statusBar);
+    layout->setMargin(2);
+    setLayout(layout);
+
+    connect(backAction, SIGNAL(triggered()), m_webView, SLOT(back()));
+    connect(forwardAction, SIGNAL(triggered()), m_webView, SLOT(forward()));
+    connect(m_webView, SIGNAL(urlChanged(QUrl)), this, SLOT(setUrl(QUrl)));
+    connect(m_urlLineEdit, SIGNAL(returnPressed()), this, SLOT(jumpToWebsite()));
+    //connect(m_webView, SIGNAL(statusBarMessage(QString)), this, SLOT(showMessage(QString)));
+}
+
+void BrowserWidget::setUrl(QUrl url) {
+    m_urlLineEdit->setText(url.toString());
+}
+
+void BrowserWidget::jumpToWebsite() {
+    QString url = m_urlLineEdit->text();
+    if(!url.startsWith("http://"))
+        url = "http://" + url;
+    load(url);
+}
+
+void BrowserWidget::showStatusMessage(QString message) {
+    m_statusBar->showMessage(message, 1000);
+}
+
+void BrowserWidget::load(QUrl url) {
+    m_webView->load(url);
+}
new file mode 100644
--- /dev/null
+++ b/gui//src/BrowserWidget.h
@@ -0,0 +1,61 @@
+/* Quint - A graphical user interface for Octave
+ * Copyright (C) 2011 Jacob Dawid
+ * jacob.dawid@googlemail.com
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef BROWSERMDISUBWINDOW_H
+#define BROWSERMDISUBWINDOW_H
+
+#include <QWidget>
+#include <QToolBar>
+#include <QLineEdit>
+#include <QtWebKit/QWebView>
+#include <QStatusBar>
+#include <QDockWidget>
+
+class BrowserWidget;
+class BrowserDockWidget : public QDockWidget {
+public:
+    BrowserDockWidget(QWidget *parent, BrowserWidget *browserWidget);
+    ~BrowserDockWidget();
+
+    BrowserWidget *browserWidget();
+
+private:
+    BrowserWidget *m_browserWidget;
+};
+
+class BrowserWidget : public QWidget {
+    Q_OBJECT
+public:
+    BrowserWidget(QWidget *parent = 0);
+    void load(QUrl url);
+
+public slots:
+    void setUrl(QUrl url);
+    void jumpToWebsite();
+    void showStatusMessage(QString message);
+
+private:
+    void construct();
+
+    QLineEdit *m_urlLineEdit;
+    QToolBar *m_navigationToolBar;
+    QWebView *m_webView;
+    QStatusBar *m_statusBar;
+};
+
+#endif // BROWSERMDISUBWINDOW_H
new file mode 100644
--- /dev/null
+++ b/gui//src/Character.h
@@ -0,0 +1,220 @@
+/*
+    This file is part of Konsole, KDE's terminal.
+    
+    Copyright 2007-2008 by Robert Knight <robertknight@gmail.com>
+    Copyright 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
+
+    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"
+
+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. 
+   */
+  ColorEntry::FontWeight fontWeight(const ColorEntry* base) const;
+  
+  /** 
+   * returns true if the format (color, rendition flag) of the compared characters is equal
+   */
+  bool equalsFormat(const Character &other) 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::equalsFormat(const Character& other) const
+{
+  return 
+    backgroundColor==other.backgroundColor &&
+    foregroundColor==other.foregroundColor &&
+    rendition==other.rendition;
+}	
+
+inline ColorEntry::FontWeight Character::fontWeight(const ColorEntry* base) const
+{
+    if (backgroundColor._colorSpace == COLOR_SPACE_DEFAULT)
+        return base[backgroundColor._u+0+(backgroundColor._v?BASE_COLORS:0)].fontWeight;
+    else if (backgroundColor._colorSpace == COLOR_SPACE_SYSTEM)
+        return base[backgroundColor._u+2+(backgroundColor._v?BASE_COLORS:0)].fontWeight;
+    else
+        return ColorEntry::UseCurrentFormat;
+}
+
+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;
+};
+
+Q_DECLARE_TYPEINFO(Character, Q_MOVABLE_TYPE);
+
+#endif // CHARACTER_H
+
new file mode 100644
--- /dev/null
+++ b/gui//src/CharacterColor.h
@@ -0,0 +1,290 @@
+/*
+    This file is part of Konsole, KDE's terminal.
+    
+    Copyright 2007-2008 by Robert Knight <robertknight@gmail.com>
+    Copyright 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
+
+    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>
+
+/** 
+ * 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:
+  /** Specifies the weight to use when drawing text with this color. */
+  enum FontWeight 
+  {
+    /** Always draw text in this color with a bold weight. */
+    Bold,
+    /** Always draw text in this color with a normal weight. */
+    Normal,
+    /** 
+     * Use the current font weight set by the terminal application.  
+     * This is the default behavior.
+     */
+    UseCurrentFormat
+  };
+
+  /** 
+   * 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 weight Specifies the font weight to use when drawing text with this color. 
+   */
+  ColorEntry(QColor c, bool tr, FontWeight weight = UseCurrentFormat) 
+          : color(c), transparent(tr), fontWeight(weight) {}
+
+  /**
+   * Constructs a new color palette entry with an undefined color, and
+   * with the transparent and bold flags set to false.
+   */ 
+  ColorEntry() : transparent(false), fontWeight(UseCurrentFormat) {} 
+ 
+  /**
+   * 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; 
+       fontWeight = rhs.fontWeight; 
+  }
+
+  /** 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;
+  /**
+   * Specifies the font weight to use when drawing text with this color. 
+   * This is not applicable when the color is used to draw a character's background.
+   */
+  FontWeight fontWeight;        
+};
+
+
+// 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
+
+extern const ColorEntry base_color_table[TABLE_COLORS];
+
+/* 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 @p 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     a._colorSpace == b._colorSpace &&
+            a._u == b._u &&
+            a._v == b._v &&
+            a._w == b._w;
+}
+inline bool operator != (const CharacterColor& a, const CharacterColor& b)
+{
+    return !operator==(a,b);
+}
+
+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(((u/36)%6) ? (40*((u/36)%6)+55) : 0,
+                             ((u/ 6)%6) ? (40*((u/ 6)%6)+55) : 0,
+                             ((u/ 1)%6) ? (40*((u/ 1)%6)+55) : 0); 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//src/ColorTables.h
@@ -0,0 +1,56 @@
+#ifndef _COLOR_TABLE_H
+#define _COLOR_TABLE_H
+
+#include "CharacterColor.h"
+
+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//src/DefaultTranslatorText.h
@@ -0,0 +1,2 @@
+"keyboard \"Fallback Key Translator\"\n"
+"key Tab : \"\\t\" \0"
new file mode 100644
--- /dev/null
+++ b/gui//src/Emulation.cpp
@@ -0,0 +1,404 @@
+/*
+    Copyright 2007-2008 Robert Knight <robertknight@gmail.com> 
+    Copyright 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
+    Copyright 1996 by Matthias Ettrich <ettrich@kde.org>
+
+    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"
+
+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;
+}
+
+void Emulation::setScreen(int n)
+{
+  Screen *old = _currentScreen;
+  _currentScreen = _screen[n & 1];
+  if (_currentScreen != old) 
+  {
+     // tell all windows onto this emulation to switch to the newly active screen
+     foreach(ScreenWindow* window,_windows)
+         window->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() const
+{
+  return _screen[0]->getScroll();
+}
+
+void Emulation::setCodec(const QTextCodec * qtc)
+{
+  if (qtc)
+      _codec = qtc;
+  else
+     setCodec(LocaleCodec);
+
+  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);
+  if (!_keyTranslator)
+  {
+      _keyTranslator = KeyboardTranslatorManager::instance()->defaultTranslator();
+  }
+}
+
+QString Emulation::keyBindings() const
+{
+  return _keyTranslator->name();
+}
+
+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->tab();                       break;
+    case '\n'      : _currentScreen->newLine();                   break;
+    case '\r'      : _currentScreen->toStartOfLine();             break;
+    case 0x07      : emit stateSet(NOTIFYBELL);
+                     break;
+    default        : _currentScreen->displayCharacter(c);         break;
+  };
+}
+
+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
+    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
+}
+
+/*
+   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();
+        }
+    }
+}
+
+void Emulation::writeToStream( TerminalCharacterDecoder* _decoder , 
+                               int startLine ,
+                               int endLine) 
+{
+  _currentScreen->writeLinesToStream(_decoder,startLine,endLine);
+}
+
+int Emulation::lineCount() const
+{
+    // sum number of lines currently on _screen plus number of lines in history
+    return _currentScreen->getLines() + _currentScreen->getHistLines();
+}
+
+#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::eraseChar() const
+{
+  return '\b';
+}
+
+void Emulation::setImageSize(int lines, int columns)
+{
+  if ((lines < 1) || (columns < 1)) 
+    return;
+
+  QSize screenSize[2] = { QSize(_screen[0]->getColumns(),
+                                _screen[0]->getLines()),
+                          QSize(_screen[1]->getColumns(),
+                                _screen[1]->getLines()) };
+  QSize newSize(columns,lines);
+
+  if (newSize == screenSize[0] && newSize == screenSize[1])
+    return;    
+
+  _screen[0]->resizeImage(lines,columns);
+  _screen[1]->resizeImage(lines,columns);
+
+  emit imageSizeChanged(lines,columns);
+
+  bufferedUpdate();
+}
+
+QSize Emulation::imageSize() const
+{
+  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;
+
+
new file mode 100644
--- /dev/null
+++ b/gui//src/Emulation.h
@@ -0,0 +1,462 @@
+/*
+    This file is part of Konsole, an X terminal.
+    
+    Copyright 2007-2008 by Robert Knight <robertknight@gmail.com>
+    Copyright 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
+
+    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 <QtCore/QTextCodec>
+#include <QtCore/QTextStream>
+#include <QtCore/QTimer>
+
+
+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() const;
+
+  /**
+   * Returns the total number of lines, including those stored in the history.
+   */ 
+  int lineCount() const;
+
+  /** 
+   * 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() const;
+  /** 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 Index of first line to copy
+   * @param endLine Index of last line to copy
+   */
+  virtual void writeToStream(TerminalCharacterDecoder* decoder,int startLine,int endLine);
+  
+  /** Returns the codec used to decode incoming characters.  See setCodec() */
+  const QTextCodec* codec() const { 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() const
+  { Q_ASSERT(_codec); return _codec->mibEnum() == 106; }
+  
+
+  /** TODO Document me */
+  virtual char eraseChar() 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() const;
+
+  /** 
+   * 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
+   * @param 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);
+
+  /** 
+   * Emitted when a flow control key combination ( Ctrl+S or Ctrl+Q ) is pressed.
+   * @param suspendKeyPressed True if Ctrl+S was pressed to suspend output or Ctrl+Q to
+   * resume output.
+   */
+  void flowControlKeyPressed(bool suspendKeyPressed);
+
+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//src/FileEditorMdiSubWindow.cpp
@@ -0,0 +1,152 @@
+/* Quint - A graphical user interface for Octave
+ * Copyright (C) 2011 Jacob Dawid
+ * jacob.dawid@googlemail.com
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "FileEditorMdiSubWindow.h"
+#include <QVBoxLayout>
+#include <QApplication>
+#include <QFile>
+#include <QFileDialog>
+#include <QMessageBox>
+#include <QAction>
+
+FileEditorMdiSubWindow::FileEditorMdiSubWindow(QWidget *parent)
+    : QMdiSubWindow(parent) {
+    construct();
+}
+
+void FileEditorMdiSubWindow::loadFile(QString fileName) {
+    m_fileName = fileName;
+    setWindowTitle(fileName);
+    m_simpleEditor->load(fileName);
+}
+
+void FileEditorMdiSubWindow::installEventFilter(QObject *object) {
+    QMdiSubWindow::installEventFilter(object);
+    m_numberedTextView->installEventFilter(object);
+    m_simpleEditor->installEventFilter(object);
+}
+
+void FileEditorMdiSubWindow::newFile() {
+    if(m_modified) {
+        int decision
+                = QMessageBox::question(this,
+                                        "Open New File",
+                                        "Do you want to save the current file?",
+                                        QMessageBox::Yes, QMessageBox::No);
+
+        if(decision == QMessageBox::Yes) {
+            saveFile();
+            if(m_modified) {
+                // If the user attempted to save the file, but it's still
+                // modified, then probably something went wrong, so we quit here.
+                return;
+            }
+        }
+    }
+
+    m_fileName = "<unnamed>";
+    setWindowTitle(m_fileName);
+    m_simpleEditor->setPlainText("");
+}
+
+void FileEditorMdiSubWindow::saveFile() {
+    QString saveFileName = QFileDialog::getSaveFileName(this, "Save File", m_fileName);
+    if(saveFileName.isEmpty())
+        return;
+
+    QFile file(saveFileName);
+    file.open(QFile::WriteOnly);
+
+    if(file.write(m_simpleEditor->toPlainText().toLocal8Bit()) == -1) {
+        QMessageBox::warning(this,
+                             "Error Saving File",
+                             QString("The file could not be saved: %1.").arg(file.errorString()));
+    } else {
+        m_simpleEditor->document()->setModified(false);
+    }
+
+    file.close();
+}
+
+void FileEditorMdiSubWindow::showToolTipNew() {
+    m_statusBar->showMessage("Create a new file.", 2000);
+}
+
+void FileEditorMdiSubWindow::showToolTipSave() {
+    m_statusBar->showMessage("Save the file.", 2000);
+}
+
+void FileEditorMdiSubWindow::showToolTipUndo() {
+    m_statusBar->showMessage("Revert previous changes.", 2000);
+}
+
+void FileEditorMdiSubWindow::showToolTipRedo() {
+    m_statusBar->showMessage("Append previous changes.", 2000);
+}
+
+void FileEditorMdiSubWindow::registerModified(bool modified) {
+    m_modified = modified;
+}
+
+void FileEditorMdiSubWindow::construct() {
+    QStyle *style = QApplication::style();
+    setWidget(new QWidget());
+    m_toolBar = new QToolBar(this);
+    m_simpleEditor = new SimpleEditor(this);
+    m_statusBar = new QStatusBar(this);
+    m_numberedTextView = new NumberedCodeEdit(this, m_simpleEditor);
+
+    m_simpleEditor->setFont(QFont("Courier"));
+    m_simpleEditor->setLineWrapMode(QPlainTextEdit::NoWrap);
+
+    QAction *newAction = new QAction(style->standardIcon(QStyle::SP_FileIcon),
+        "", m_toolBar);
+    QAction *saveAction = new QAction(style->standardIcon(QStyle::SP_DriveHDIcon),
+        "", m_toolBar);
+    QAction *undoAction = new QAction(style->standardIcon(QStyle::SP_ArrowLeft),
+        "", m_toolBar);
+    QAction *redoAction = new QAction(style->standardIcon(QStyle::SP_ArrowRight),
+        "", m_toolBar);
+
+    m_toolBar->addAction(newAction);
+    m_toolBar->addAction(saveAction);
+    m_toolBar->addAction(undoAction);
+    m_toolBar->addAction(redoAction);
+
+    QVBoxLayout *layout = new QVBoxLayout();
+    layout->addWidget(m_toolBar);
+    layout->addWidget(m_numberedTextView);
+    layout->addWidget(m_statusBar);
+    layout->setMargin(2);
+    widget()->setLayout(layout);
+
+    connect(newAction, SIGNAL(triggered()), this, SLOT(newFile()));
+    connect(undoAction, SIGNAL(triggered()), m_simpleEditor, SLOT(undo()));
+    connect(redoAction, SIGNAL(triggered()), m_simpleEditor, SLOT(redo()));
+    connect(saveAction, SIGNAL(triggered()), this, SLOT(saveFile()));
+
+    connect(newAction, SIGNAL(hovered()), this, SLOT(showToolTipNew()));
+    connect(undoAction, SIGNAL(hovered()), this, SLOT(showToolTipUndo()));
+    connect(redoAction, SIGNAL(hovered()), this, SLOT(showToolTipRedo()));
+    connect(saveAction, SIGNAL(hovered()), this, SLOT(showToolTipSave()));
+
+    connect(m_simpleEditor, SIGNAL(modificationChanged(bool)), this, SLOT(registerModified(bool)));
+
+    m_fileName = "";
+    setWindowTitle(m_fileName);
+}
new file mode 100644
--- /dev/null
+++ b/gui//src/FileEditorMdiSubWindow.h
@@ -0,0 +1,56 @@
+/* Quint - A graphical user interface for Octave
+ * Copyright (C) 2011 Jacob Dawid
+ * jacob.dawid@googlemail.com
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef FILEEDITORMDISUBWINDOW_H
+#define FILEEDITORMDISUBWINDOW_H
+
+#include <QMdiSubWindow>
+#include <QToolBar>
+#include <QStatusBar>
+#include "SimpleEditor.h"
+#include "NumberedCodeEdit.h"
+
+class FileEditorMdiSubWindow : public QMdiSubWindow {
+    Q_OBJECT
+public:
+    FileEditorMdiSubWindow(QWidget *parent = 0);
+    void loadFile(QString fileName);
+
+    void installEventFilter(QObject *object);
+
+public slots:
+    void newFile();
+    void saveFile();
+
+    void showToolTipNew();
+    void showToolTipSave();
+    void showToolTipUndo();
+    void showToolTipRedo();
+
+    void registerModified(bool modified);
+private:
+    void construct();
+    QToolBar *m_toolBar;
+    SimpleEditor *m_simpleEditor;
+    NumberedCodeEdit *m_numberedTextView;
+    QStatusBar *m_statusBar;
+    QString m_fileName;
+    bool m_modified;
+};
+
+#endif // FILEEDITORMDISUBWINDOW_H
new file mode 100644
--- /dev/null
+++ b/gui//src/FilesDockWidget.cpp
@@ -0,0 +1,98 @@
+#include "FilesDockWidget.h"
+
+#include <QApplication>
+#include <QFileInfo>
+
+FilesDockWidget::FilesDockWidget(QWidget *parent)
+  : QDockWidget(parent) {
+    setObjectName("FilesDockWidget");
+    setWindowTitle(tr("Current Folder"));
+    setWidget(new QWidget(this));
+
+    // Create a toolbar
+    m_navigationToolBar = new QToolBar("", widget());
+    m_navigationToolBar->setAllowedAreas(Qt::TopToolBarArea);
+    m_navigationToolBar->setMovable(false);
+    m_navigationToolBar->setIconSize(QSize (20,20));
+
+    // Add a button to the toolbar with the QT standard icon for up-directory
+    // TODO: Maybe change this to be an up-directory icon that is OS specific???
+    QStyle *style = QApplication::style();
+    m_directoryIcon = style->standardIcon(QStyle::SP_FileDialogToParent);
+    m_directoryUpAction = new QAction(m_directoryIcon, "", m_navigationToolBar);
+    m_currentDirectory = new QLineEdit(m_navigationToolBar);
+
+    m_navigationToolBar->addAction(m_directoryUpAction);
+    m_navigationToolBar->addWidget(m_currentDirectory);
+    connect(m_directoryUpAction, SIGNAL(triggered()), this, SLOT(onUpDirectory()));
+
+    // TODO: Add other buttons for creating directories
+
+    // Create the QFileSystemModel starting in the home directory
+    QString homePath = QDir::homePath();
+    // TODO: This should occur after Octave has been initialized and the startup directory of Octave is established
+
+    m_fileSystemModel = new QFileSystemModel(this);
+    m_fileSystemModel->setFilter(QDir::NoDotAndDotDot | QDir::AllEntries);
+    QModelIndex rootPathIndex = m_fileSystemModel->setRootPath(homePath);
+
+    // Attach the model to the QTreeView and set the root index
+    m_fileTreeView = new QTreeView(widget());
+    m_fileTreeView->setModel(m_fileSystemModel);
+    m_fileTreeView->setRootIndex(rootPathIndex);
+    m_fileTreeView->setSortingEnabled(true);
+    m_fileTreeView->setAlternatingRowColors(true);
+    m_fileTreeView->setAnimated(true);
+    setCurrentDirectory(m_fileSystemModel->fileInfo(rootPathIndex).absoluteFilePath());
+
+    connect(m_fileTreeView, SIGNAL(doubleClicked(const QModelIndex &)), this, SLOT(itemDoubleClicked(const QModelIndex &)));
+
+    // Layout the widgets vertically with the toolbar on top
+    QVBoxLayout *layout = new QVBoxLayout();
+    layout->setSpacing(0);
+    layout->addWidget(m_navigationToolBar);
+    layout->addWidget(m_fileTreeView);
+    widget()->setLayout(layout);
+    // TODO: Add right-click contextual menus for copying, pasting, deleting files (and others)
+
+    connect(m_currentDirectory, SIGNAL(returnPressed()), this, SLOT(currentDirectoryEntered()));
+    //m_currentDirectory->setEnabled(false);
+}
+
+void FilesDockWidget::itemDoubleClicked(const QModelIndex &index)
+{
+    QFileInfo fileInfo = m_fileSystemModel->fileInfo(index);
+    if (fileInfo.isDir()) {
+        m_fileSystemModel->setRootPath(fileInfo.absolutePath());
+        m_fileTreeView->setRootIndex(index);
+        setCurrentDirectory(m_fileSystemModel->fileInfo(index).absoluteFilePath());
+    } else {
+        QFileInfo fileInfo = m_fileSystemModel->fileInfo(index);
+        emit openFile(fileInfo.filePath());
+    }
+}
+
+void FilesDockWidget::setCurrentDirectory(QString currentDirectory) {
+    m_currentDirectory->setText(currentDirectory);
+}
+
+void FilesDockWidget::onUpDirectory(void) {
+    // Move up an inm_fileTreeView->setRootIndex(m_fileSystemModel->index(dir.absolutePath()));dex node
+    QDir dir = QDir(m_fileSystemModel->filePath(m_fileTreeView->rootIndex()));
+    dir.cdUp();
+    m_fileSystemModel->setRootPath(dir.absolutePath());
+    m_fileTreeView->setRootIndex(m_fileSystemModel->index(dir.absolutePath()));
+    setCurrentDirectory(dir.absolutePath());
+}
+
+void FilesDockWidget::currentDirectoryEntered() {
+    QFileInfo fileInfo(m_currentDirectory->text());
+    if (fileInfo.isDir()) {
+        m_fileTreeView->setRootIndex(m_fileSystemModel->index(fileInfo.absolutePath()));
+        m_fileSystemModel->setRootPath(fileInfo.absolutePath());
+        setCurrentDirectory(fileInfo.absoluteFilePath());
+    } else {
+        if(QFile::exists(fileInfo.absoluteFilePath()))
+            emit openFile(fileInfo.absoluteFilePath());
+    }
+}
new file mode 100644
--- /dev/null
+++ b/gui//src/FilesDockWidget.h
@@ -0,0 +1,86 @@
+/* Quint - A graphical user interface for Octave
+ * Copyright (C) 2011 John P. Swensen, Jacob Dawid
+ * jacob.dawid@googlemail.com
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef FILESDOCKWIDGET_H
+#define FILESDOCKWIDGET_H
+
+#include <QListView>
+#include <QDate>
+#include <QObject>
+#include <QWidget>
+#include <QListWidget>
+#include <QFileSystemModel>
+#include <QToolBar>
+#include <QToolButton>
+#include <QVBoxLayout>
+#include <QAction>
+#include <QTreeView>
+
+#include <vector>
+#include <string>
+
+#undef PACKAGE_BUGREPORT
+#undef PACKAGE_NAME
+#undef PACKAGE_STRING
+#undef PACKAGE_TARNAME
+#undef PACKAGE_VERSION
+#include "octave/config.h"
+#include "octave/octave.h"
+#include "octave/str-vec.h"
+#include "octave/cmd-hist.h"
+#include <QDockWidget>
+#include <QLineEdit>
+
+class FilesDockWidget : public QDockWidget {
+    Q_OBJECT
+public :
+    FilesDockWidget(QWidget *parent = 0);
+public slots:
+    /** Slot for handling a change in directory via double click. */
+    void itemDoubleClicked(const QModelIndex &index);
+
+    /** Slot for handling the up-directory button in the toolbar. */
+    void onUpDirectory();
+
+    void setCurrentDirectory(QString currentDirectory);
+
+    void currentDirectoryEntered();
+
+signals:
+    void openFile(QString fileName);
+
+private:
+    // TODO: Add toolbar with buttons for navigating the path, creating dirs, etc
+
+    /** Toolbar for file and directory manipulation. */
+    QToolBar *m_navigationToolBar;
+
+    /** Variables for the up-directory action. */
+    QIcon m_directoryIcon;
+    QAction *m_directoryUpAction;
+    QToolButton *upDirectoryButton;
+
+    /** The file system model. */
+    QFileSystemModel *m_fileSystemModel;
+
+    /** The file system view. */
+    QTreeView *m_fileTreeView;
+    QLineEdit *m_currentDirectory;
+};
+
+#endif // FILESDOCKWIDGET_H
new file mode 100644
--- /dev/null
+++ b/gui//src/Filter.cpp
@@ -0,0 +1,534 @@
+/*
+    Copyright 2007-2008 by Robert Knight <robertknight@gmail.com>
+
+    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/QTextStream>
+#include <QtCore/QSharedData>
+#include <QtCore/QFile>
+
+// Konsole
+#include "TerminalCharacterDecoder.h"
+#include "konsole_wcwidth.h"
+#include "konsole_export.h"
+
+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)
+{
+    if (empty())
+        return;
+
+    // reset all filters and hotspots
+    reset();
+
+    PlainTextDecoder decoder;
+    decoder.setTrailingWhitespace(false);
+    
+    // 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();
+}
+
+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++)
+    {
+        int nextLine = 0;
+
+        if ( i == _linePositions->count()-1 )
+            nextLine = _buffer->length() + 1;
+        else
+            nextLine = _linePositions->value(i+1);
+
+        if ( _linePositions->value(i) <= position && position < nextLine ) 
+        {
+            startLine = i;
+            startColumn = string_width(buffer()->mid(_linePositions->value(i),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;
+
+            getLineColumn(pos,startLine,startColumn);
+            getLineColumn(pos + _searchText.matchedLength(),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
+            if ( _searchText.matchedLength() == 0 )
+                pos = -1;
+        }
+    }    
+}
+
+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" )
+    {
+        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(i18n("Open Link"));
+        copyAction->setText(i18n("Copy Link Address"));
+    }
+    else if ( kind == Email )
+    {
+        openAction->setText(i18n("Send Email To..."));
+        copyAction->setText(i18n("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( QLatin1String("open-action" ));
+    copyAction->setObjectName( QLatin1String("copy-action" ));
+
+    QObject::connect( openAction , SIGNAL(triggered()) , _urlObject , SLOT(activated()) );
+    QObject::connect( copyAction , SIGNAL(triggered()) , _urlObject , SLOT(activated()) );
+
+    list << openAction;
+    list << copyAction;
+
+    return list; 
+}
+
new file mode 100644
--- /dev/null
+++ b/gui//src/Filter.h
@@ -0,0 +1,379 @@
+/*
+    Copyright 2007-2008 by Robert Knight <robertknight@gmail.com>
+
+    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"
+
+
+/**
+ * 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
+     * @param lineProperties The line properties to set for 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//src/History.cpp
@@ -0,0 +1,696 @@
+/*
+    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
+
+/*
+   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//src/History.h
@@ -0,0 +1,307 @@
+/*
+    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 HISTORY_H
+#define HISTORY_H
+
+// Qt
+#include <QtCore/QBitRef>
+#include <QtCore/QHash>
+#include <QtCore>
+
+// Konsole
+#include "BlockArray.h"
+#include "Character.h"
+
+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;
+};
+
+//////////////////////////////////////////////////////////////////////
+
+//////////////////////////////////////////////////////////////////////
+// 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;
+
+};
+
+
+
+//////////////////////////////////////////////////////////////////////
+// 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;
+};
+
+//////////////////////////////////////////////////////////////////////
+// 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;
+};
+
+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 // HISTORY_H
new file mode 100644
--- /dev/null
+++ b/gui//src/HistoryDockWidget.cpp
@@ -0,0 +1,61 @@
+/* Quint - A graphical user interface for Octave
+ * Copyright (C) 2011 Jacob Dawid
+ * jacob.dawid@googlemail.com
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "HistoryDockWidget.h"
+#include <QHBoxLayout>
+
+HistoryDockWidget::HistoryDockWidget(QWidget *parent)
+    : QDockWidget(parent) {
+    setObjectName("HistoryDockWidget");
+    construct();
+}
+
+void HistoryDockWidget::handleListViewItemDoubleClicked(QModelIndex modelIndex) {
+    QString command = m_historyListModel->data(modelIndex, 0).toString();
+    emit commandDoubleClicked(command);
+}
+
+void HistoryDockWidget::construct() {
+    m_historyListModel = new QStringListModel();
+    m_historyListView = new QListView(this);
+    m_historyListView->setModel(m_historyListModel);
+    m_historyListView->setAlternatingRowColors(true);
+    m_historyListView->setEditTriggers(QAbstractItemView::NoEditTriggers);
+    QHBoxLayout *layout = new QHBoxLayout();
+
+    setWindowTitle(tr("Command History"));
+    setWidget(new QWidget());
+
+    layout->addWidget(m_historyListView);
+    layout->setMargin(2);
+
+    widget()->setLayout(layout);
+    connect(m_historyListView, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(handleListViewItemDoubleClicked(QModelIndex)));
+}
+
+void HistoryDockWidget::updateHistory(string_vector historyEntries) {
+    QStringList stringList = m_historyListModel->stringList();
+    for(int i = 0; i < historyEntries.length(); i++) {
+        QString command(historyEntries[i].c_str());
+        if(!command.startsWith("#")) {
+            stringList.push_front(command);
+        }
+    }
+    m_historyListModel->setStringList(stringList);
+    emit information(tr("History updated."));
+}
new file mode 100644
--- /dev/null
+++ b/gui//src/HistoryDockWidget.h
@@ -0,0 +1,55 @@
+#ifndef HISTORYDOCKWIDGET_H
+#define HISTORYDOCKWIDGET_H
+
+#include <QDockWidget>
+#include <QListView>
+#include <QStringListModel>
+
+// Octave includes
+#undef PACKAGE_BUGREPORT
+#undef PACKAGE_NAME
+#undef PACKAGE_STRING
+#undef PACKAGE_TARNAME
+#undef PACKAGE_VERSION
+#undef PACKAGE_URL
+#include "octave/config.h"
+
+#include "octave/debug.h"
+#include "octave/octave.h"
+#include "octave/symtab.h"
+#include "octave/parse.h"
+#include "octave/unwind-prot.h"
+#include "octave/toplev.h"
+#include "octave/load-path.h"
+#include "octave/error.h"
+#include "octave/quit.h"
+#include "octave/variables.h"
+#include "octave/sighandlers.h"
+#include "octave/sysdep.h"
+#include "octave/str-vec.h"
+#include "octave/cmd-hist.h"
+#include "octave/cmd-edit.h"
+#include "octave/oct-env.h"
+#include "octave/symtab.h"
+#include "cmd-edit.h"
+
+class HistoryDockWidget : public QDockWidget {
+    Q_OBJECT
+public:
+    HistoryDockWidget(QWidget *parent = 0);
+    void updateHistory(string_vector historyEntries);
+
+signals:
+    void information(QString message);
+    void commandDoubleClicked(QString command);
+
+private slots:
+    void handleListViewItemDoubleClicked(QModelIndex modelIndex);
+
+private:
+    void construct();
+    QListView *m_historyListView;
+    QStringListModel *m_historyListModel;
+};
+
+#endif // HISTORYDOCKWIDGET_H
new file mode 100644
--- /dev/null
+++ b/gui//src/ImageViewerMdiSubWindow.cpp
@@ -0,0 +1,23 @@
+#include "ImageViewerMdiSubWindow.h"
+#include <QLabel>
+#include <QPixmap>
+#include <QScrollArea>
+
+ImageViewerMdiSubWindow::ImageViewerMdiSubWindow(QPixmap pixmap, QWidget *parent)
+    : QMdiSubWindow(parent),
+      m_pixmap(pixmap) {
+    construct();
+}
+
+void ImageViewerMdiSubWindow::construct() {
+    QLabel *label = new QLabel();
+    label->setBackgroundRole(QPalette::Base);
+    label->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
+    label->setScaledContents(true);
+    label->setPixmap(m_pixmap);
+
+    QScrollArea *scrollArea = new QScrollArea(this);
+    scrollArea->setBackgroundRole(QPalette::Dark);
+    scrollArea->setWidget(label);
+    setWidget(scrollArea);
+}
new file mode 100644
--- /dev/null
+++ b/gui//src/ImageViewerMdiSubWindow.h
@@ -0,0 +1,16 @@
+#ifndef IMAGEVIEWERMDISUBWINDOW_H
+#define IMAGEVIEWERMDISUBWINDOW_H
+
+#include <QMdiSubWindow>
+
+class ImageViewerMdiSubWindow : public QMdiSubWindow
+{
+public:
+    ImageViewerMdiSubWindow(QPixmap pixmap, QWidget *parent = 0);
+
+private:
+    void construct();
+    QPixmap m_pixmap;
+};
+
+#endif // IMAGEVIEWERMDISUBWINDOW_H
new file mode 100644
--- /dev/null
+++ b/gui//src/KeyboardTranslator.cpp
@@ -0,0 +1,970 @@
+/*
+    This source file is part of Konsole, a terminal emulator.
+
+    Copyright 2007-2008 by Robert Knight <robertknight@gmail.com>
+
+    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 <QtCore/QFile>
+#include <QtCore/QFileInfo>
+#include <QtCore/QTextStream>
+#include <QtGui/QKeySequence>
+#include <QtCore/QDir>
+#include <QtCore/QStringList>
+#include <QtCore/QDebug>
+#include <QtCore/QDataStream>
+
+const QByteArray KeyboardTranslatorManager::defaultTranslatorText(
+"keyboard \"Fallback Key Translator\"\n"
+"key Tab : \"\\t\""
+);
+
+KeyboardTranslatorManager::KeyboardTranslatorManager()
+    : _haveLoadedAll(false)
+{
+}
+KeyboardTranslatorManager::~KeyboardTranslatorManager()
+{
+    qDeleteAll(_translators);
+}
+QString KeyboardTranslatorManager::findTranslatorPath(const QString& name)
+{
+  return QString("../kb-layouts/" + name + ".keytab");
+  // return KGlobal::dirs()->findResource("data","konsole/"+name+".keytab");
+}
+void KeyboardTranslatorManager::findTranslators()
+{
+  //QStringList list = KGlobal::dirs()->findAllResources("data",
+  //                                                     "konsole/*.keytab",
+  //                                                     KStandardDirs::NoDuplicates);
+
+    QDir dir("../kb-layouts/");
+    QStringList filters;
+    filters << "*.keytab";
+    dir.setNameFilters(filters);
+    QStringList 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();
+
+    if ( _translators.contains(name) && _translators[name] != 0 )
+        return _translators[name];
+
+    KeyboardTranslator* translator = loadTranslator(name);
+
+    if ( translator != 0 )
+        _translators[name] = translator;
+    //else if ( !name.isEmpty() )
+    //  kWarning() << "Unable to load translator" << name;
+
+    return translator;
+}
+
+bool KeyboardTranslatorManager::saveTranslator(const KeyboardTranslator* translator)
+{
+  //const QString path = KGlobal::dirs()->saveLocation("data","konsole/")+translator->name()
+  //         +".keytab";
+  const QString path = ".keytab";
+
+    //kDebug() << "Saving translator to" << path;
+
+    QFile destination(path);
+    if (!destination.open(QIODevice::WriteOnly | QIODevice::Text))
+    {
+        //kWarning() << "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()
+{
+    // Try to find the default.keytab file if it exists, otherwise
+    // fall back to the hard-coded one
+    const KeyboardTranslator* translator = findTranslator("default");
+    if (!translator)
+    {
+        QBuffer textBuffer;
+        textBuffer.setData(defaultTranslatorText);
+        textBuffer.open(QIODevice::ReadOnly);
+        translator = loadTranslator(&textBuffer,"fallback");
+    }
+    return translator;
+}
+
+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() )
+   {
+        QList<Token> tokens = tokenize( QString(source->readLine()) );
+        if ( !tokens.isEmpty() && tokens.first().type == Token::TitleKeyword )
+            _description = QString(tokens[1].text.toLatin1().data());
+   }
+   // read first entry (if any)
+   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))
+                //  kWarning() << "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 isFirstLetter = i == 0;
+        bool isLastLetter = ( i == text.count()-1 );
+        endOfItem = true;
+        if ( ch.isLetterOrNumber() )
+        {
+            endOfItem = false;
+            buffer.append(ch);
+        } else if ( isFirstLetter )
+        {
+            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
+          //      kWarning() << "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" || item == "appcursorkeys" )
+        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" || item == "anymodifier" )
+        flag = KeyboardTranslator::AnyModifierState;
+    else if ( item == "appkeypad" )
+        flag = KeyboardTranslator::ApplicationKeypadState;
+    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 )
+        {
+            //kWarning() << "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();
+    QBuffer buffer(&array);
+    buffer.open(QIODevice::ReadOnly);
+    KeyboardTranslatorReader reader(&buffer);
+
+    KeyboardTranslator::Entry entry;
+    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;
+
+    // remove comments 
+    bool inQuotes = false;
+    int commentPos = -1;
+    for (int i=text.length()-1;i>=0;i--)
+    {
+        QChar ch = text[i];
+        if (ch == '\"')
+            inQuotes = !inQuotes;
+        else if (ch == '#' && !inQuotes)
+            commentPos = i;
+    }
+    if (commentPos != -1)
+        text.remove(commentPos,text.length());
+
+    text = text.simplified();
+   
+    // 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() ) 
+    {
+        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
+    {
+        //kWarning() << "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 testState) 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 )
+        testState |= AnyModifierState;
+
+    if ( (testState & _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;
+    bool wantAnyModifier = _state & KeyboardTranslator::AnyModifierState;
+    if ( _stateMask & KeyboardTranslator::AnyModifierState )
+    {
+        if ( wantAnyModifier != 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).toHex()); 
+        } 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];
+
+                    unsigned 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 += "AppCursorKeys";
+    else if ( state == KeyboardTranslator::AnyModifierState )
+        item += "AnyModifier";
+    else if ( state == KeyboardTranslator::ApplicationKeypadState )
+        item += "AppKeypad";
+}
+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();
+
+    insertModifier( result , Qt::ShiftModifier );
+    insertModifier( result , Qt::ControlModifier );
+    insertModifier( result , Qt::AltModifier );
+    insertModifier( result , Qt::MetaModifier );
+    insertModifier( result , Qt::KeypadModifier );
+
+    insertState( result , KeyboardTranslator::AlternateScreenState );
+    insertState( result , KeyboardTranslator::NewLineState );
+    insertState( result , KeyboardTranslator::AnsiState );
+    insertState( result , KeyboardTranslator::CursorKeysState );
+    insertState( result , KeyboardTranslator::AnyModifierState );
+    insertState( result , KeyboardTranslator::ApplicationKeypadState );
+
+    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.insert(keyCode,entry);
+}
+void KeyboardTranslator::replaceEntry(const Entry& existing , const Entry& replacement)
+{
+    if ( !existing.isNull() )
+        _entries.remove(existing.keyCode(),existing);
+    _entries.insert(replacement.keyCode(),replacement);
+}
+void KeyboardTranslator::removeEntry(const Entry& entry)
+{
+    _entries.remove(entry.keyCode(),entry);
+}
+KeyboardTranslator::Entry KeyboardTranslator::findEntry(int keyCode, Qt::KeyboardModifiers modifiers, States state) const
+{
+    foreach(const Entry& entry, _entries.values(keyCode))
+    {
+        if ( entry.matches(keyCode,modifiers,state) )
+            return entry;
+    }
+    return Entry(); // entry not found
+}
+void KeyboardTranslatorManager::addTranslator(KeyboardTranslator* translator)
+{
+    _translators.insert(translator->name(),translator);
+
+  //  if ( !saveTranslator(translator) )
+  //      kWarning() << "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
+    {
+        //kWarning() << "Failed to remove translator - " << path;
+        return false;
+    }
+}
+
+/**
+ * @internal
+ */
+typedef void (*KdeCleanUpFunction)();
+
+/**
+ * @internal
+ *
+ * Helper class for K_GLOBAL_STATIC to clean up the object on library unload or application
+ * shutdown.
+ */
+class KCleanUpGlobalStatic
+{
+    public:
+        KdeCleanUpFunction func;
+
+        inline ~KCleanUpGlobalStatic() { func(); }
+};
+
+
+
+#ifdef Q_CC_MSVC
+/**
+ * @internal
+ *
+ * MSVC seems to give anonymous structs the same name which fails at link time. So instead we name
+ * the struct and hope that by adding the line number to the name it's unique enough to never clash.
+ */
+# define K_GLOBAL_STATIC_STRUCT_NAME(NAME) _k_##NAME##__LINE__
+#else
+/**
+ * @internal
+ *
+ * Make the struct of the K_GLOBAL_STATIC anonymous.
+ */
+# define K_GLOBAL_STATIC_STRUCT_NAME(NAME)
+#endif
+
+
+
+#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)                                \
+{                                                                              \
+    inline bool isDestroyed() const                                            \
+    {                                                                          \
+        return _k_static_##NAME##_destroyed;                                   \
+    }                                                                          \
+    inline bool exists() const                                                 \
+    {                                                                          \
+        return _k_static_##NAME != 0;                                          \
+    }                                                                          \
+    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 KCleanUpGlobalStatic 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;
+
+#define K_GLOBAL_STATIC(TYPE, NAME) K_GLOBAL_STATIC_WITH_ARGS(TYPE, NAME, ())
+
+K_GLOBAL_STATIC( KeyboardTranslatorManager , theKeyboardTranslatorManager )
+KeyboardTranslatorManager* KeyboardTranslatorManager::instance()
+{
+    return theKeyboardTranslatorManager;
+}
new file mode 100644
--- /dev/null
+++ b/gui//src/KeyboardTranslator.h
@@ -0,0 +1,577 @@
+/*
+    This source file is part of Konsole, a terminal emulator.
+
+    Copyright 2007-2008 by Robert Knight <robertknight@gmail.com>
+
+    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>
+
+class QIODevice;
+class QTextStream;
+
+/** 
+ * 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,
+        /** Indicates that the numpad is in application mode. */
+        ApplicationKeypadState = 32
+    };
+    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:
+
+    QMultiHash<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 QByteArray 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(KeyboardTranslator::Entry)
+Q_DECLARE_METATYPE(const KeyboardTranslator*)
+
+#endif // KEYBOARDTRANSLATOR_H
+
new file mode 100644
--- /dev/null
+++ b/gui//src/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//src/MainWindow.cpp
@@ -0,0 +1,190 @@
+/* Quint - A graphical user interface for Octave
+ * Copyright (C) 2011 Jacob Dawid
+ * jacob.dawid@googlemail.com
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <QMenuBar>
+#include <QMenu>
+#include <QAction>
+#include <QSettings>
+#include <QDesktopServices>
+#include <QFileDialog>
+#include "MainWindow.h"
+#include "FileEditorDockWidget.h"
+#include "ImageViewerDockWidget.h"
+
+MainWindow::MainWindow(QWidget *parent)
+    : QMainWindow(parent),
+      m_isRunning(true) {
+    setObjectName("MainWindow");
+
+    QDesktopServices desktopServices;
+    m_settingsFile = desktopServices.storageLocation(QDesktopServices::HomeLocation) + "/.quint/settings.ini";
+    construct();
+    establishOctaveLink();
+}
+
+MainWindow::~MainWindow() {
+}
+
+void MainWindow::handleOpenFileRequest(QString fileName) {
+    reportStatusMessage(tr("Opening file."));
+    QPixmap pixmap;
+    if(pixmap.load(fileName)) {
+        ImageViewerDockWidget *imageViewerDockWidget = new ImageViewerDockWidget(pixmap, this);
+        imageViewerDockWidget->setWindowTitle(fileName);
+        addDockWidget(Qt::RightDockWidgetArea, imageViewerDockWidget);
+    } else {
+        FileEditorDockWidget *fileEditorDockWidget = new FileEditorDockWidget(this);
+        fileEditorDockWidget->loadFile(fileName);
+        addDockWidget(Qt::RightDockWidgetArea, fileEditorDockWidget);
+    }
+}
+
+void MainWindow::reportStatusMessage(QString statusMessage) {
+    m_statusBar->showMessage(statusMessage, 1000);
+}
+
+void MainWindow::handleSaveWorkspaceRequest() {
+    QDesktopServices desktopServices;
+    QString selectedFile = QFileDialog::getSaveFileName(this, tr("Save Workspace"),
+        desktopServices.storageLocation(QDesktopServices::HomeLocation) + "/.quint/workspace");
+    m_octaveTerminalDockWidget->octaveTerminal()->sendText(QString("save \'%1\'\n").arg(selectedFile));
+    m_octaveTerminalDockWidget->octaveTerminal()->setFocus();
+}
+
+void MainWindow::handleLoadWorkspaceRequest() {
+    QDesktopServices desktopServices;
+    QString selectedFile = QFileDialog::getOpenFileName(this, tr("Load Workspace"),
+        desktopServices.storageLocation(QDesktopServices::HomeLocation) + "/.quint/workspace");
+    m_octaveTerminalDockWidget->octaveTerminal()->sendText(QString("load \'%1\'\n").arg(selectedFile));
+    m_octaveTerminalDockWidget->octaveTerminal()->setFocus();
+}
+
+void MainWindow::handleClearWorkspaceRequest() {
+    m_octaveTerminalDockWidget->octaveTerminal()->sendText("clear\n");
+    m_octaveTerminalDockWidget->octaveTerminal()->setFocus();
+}
+
+void MainWindow::handleCommandDoubleClicked(QString command) {
+    m_octaveTerminalDockWidget->octaveTerminal()->sendText(command);
+    m_octaveTerminalDockWidget->octaveTerminal()->setFocus();
+}
+
+void MainWindow::closeEvent(QCloseEvent *closeEvent) {
+    m_isRunning = false;
+    reportStatusMessage(tr("Saving data and shutting down."));
+    writeSettings();
+
+    m_octaveCallbackThread->terminate();
+    m_octaveCallbackThread->wait();
+
+    m_octaveMainThread->terminate();
+    QMainWindow::closeEvent(closeEvent);
+}
+
+void MainWindow::readSettings() {
+    QSettings settings(m_settingsFile, QSettings::IniFormat);
+    restoreGeometry(settings.value("MainWindow/geometry").toByteArray());
+    restoreState(settings.value("MainWindow/windowState").toByteArray());
+}
+
+void MainWindow::writeSettings() {
+    QSettings settings(m_settingsFile, QSettings::IniFormat);
+    settings.setValue("MainWindow/geometry", saveGeometry());
+    settings.setValue("MainWindow/windowState", saveState());
+}
+
+void MainWindow::construct() {
+    setWindowTitle("Octave");
+    setWindowIcon(QIcon("../media/quint_icon_small.png"));
+    QStyle *style = QApplication::style();
+    resize(800, 600);
+
+    m_octaveTerminalDockWidget = new OctaveTerminalDockWidget(this, new OctaveTerminal(this));
+    m_variablesDockWidget = new VariablesDockWidget(this);
+    m_historyDockWidget = new HistoryDockWidget(this);
+    m_filesDockWidget = new FilesDockWidget(this);
+    m_browserDockWidget = new BrowserDockWidget(this, new BrowserWidget(this));
+    m_serviceDockWidget = new BrowserDockWidget(this, new BrowserWidget(this));
+
+    m_browserDockWidget->setObjectName("BrowserWidget");
+    m_browserDockWidget->setWindowTitle(tr("Documentation"));
+    m_serviceDockWidget->setObjectName("ServiceWidget");
+    m_serviceDockWidget->setWindowTitle(tr("Service"));
+
+    // This is needed, since a QMainWindow without a central widget is not supported.
+    setCentralWidget(new QWidget(this));
+    centralWidget()->setObjectName("CentralWidget");
+    centralWidget()->hide();
+
+    setDockOptions(QMainWindow::AllowTabbedDocks | QMainWindow::AllowNestedDocks | QMainWindow::AnimatedDocks);
+
+    addDockWidget(Qt::RightDockWidgetArea, m_octaveTerminalDockWidget);
+    addDockWidget(Qt::LeftDockWidgetArea, m_variablesDockWidget);
+    addDockWidget(Qt::LeftDockWidgetArea, m_historyDockWidget);
+    addDockWidget(Qt::LeftDockWidgetArea, m_filesDockWidget);
+    addDockWidget(Qt::LeftDockWidgetArea, m_browserDockWidget);
+    addDockWidget(Qt::LeftDockWidgetArea, m_serviceDockWidget);
+
+    // TODO: Add meaningfull toolbar items.
+    m_generalPurposeToolbar = new QToolBar(tr("Octave Toolbar"), this);
+    QAction *commandAction = new QAction(style->standardIcon(QStyle::SP_CommandLink),
+        "", m_generalPurposeToolbar);
+    QAction *computerAction = new QAction(style->standardIcon(QStyle::SP_ComputerIcon),
+        "", m_generalPurposeToolbar);
+    m_generalPurposeToolbar->addAction(commandAction);
+    m_generalPurposeToolbar->addAction(computerAction);
+    addToolBar(m_generalPurposeToolbar);
+
+    // Create status bar.
+
+    m_statusBar = new QStatusBar(this);
+    setStatusBar(m_statusBar);
+
+    readSettings();
+
+    connect(m_filesDockWidget, SIGNAL(openFile(QString)), this, SLOT(handleOpenFileRequest(QString)));
+    connect(m_historyDockWidget, SIGNAL(information(QString)), this, SLOT(reportStatusMessage(QString)));
+    connect(m_historyDockWidget, SIGNAL(commandDoubleClicked(QString)), this, SLOT(handleCommandDoubleClicked(QString)));
+    connect(m_variablesDockWidget, SIGNAL(saveWorkspace()), this, SLOT(handleSaveWorkspaceRequest()));
+    connect(m_variablesDockWidget, SIGNAL(loadWorkspace()), this, SLOT(handleLoadWorkspaceRequest()));
+    connect(m_variablesDockWidget, SIGNAL(clearWorkspace()), this, SLOT(handleClearWorkspaceRequest()));
+
+    m_browserDockWidget->browserWidget()->load(QUrl("http://www.gnu.org/software/octave/doc/interpreter/"));
+    m_serviceDockWidget->browserWidget()->load(QUrl("http://powerup.ath.cx/bugtracker"));
+
+}
+
+void MainWindow::establishOctaveLink() {
+    m_octaveMainThread = new OctaveMainThread(this);
+    m_octaveMainThread->start();
+
+    m_octaveCallbackThread = new OctaveCallbackThread(this, this);
+    m_octaveCallbackThread->start();
+
+    command_editor::add_event_hook(OctaveLink::readlineEventHook);
+
+    int fdm, fds;
+    if(openpty(&fdm, &fds, 0, 0, 0) < 0) {
+        assert(0);
+    }
+    dup2 (fds, 0);
+    dup2 (fds, 1);
+    dup2 (fds, 2);
+    m_octaveTerminalDockWidget->octaveTerminal()->openTeletype(fdm);
+    reportStatusMessage(tr("Established link to Octave."));
+}
new file mode 100644
--- /dev/null
+++ b/gui//src/MainWindow.h
@@ -0,0 +1,180 @@
+/* Quint - A graphical user interface for Octave
+ * Copyright (C) 2011 Jacob Dawid
+ * jacob.dawid@googlemail.com
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
+
+#include <QtGui/QMainWindow>
+#include <QThread>
+#include <QTabWidget>
+#include <QMdiArea>
+#include <QStatusBar>
+#include <QToolBar>
+#include <QQueue>
+#include "OctaveTerminal.h"
+#include "OctaveLink.h"
+#include "VariablesDockWidget.h"
+#include "HistoryDockWidget.h"
+#include "FilesDockWidget.h"
+#include "SimpleEditor.h"
+#include "BrowserWidget.h"
+
+// Octave includes
+#undef PACKAGE_BUGREPORT
+#undef PACKAGE_NAME
+#undef PACKAGE_STRING
+#undef PACKAGE_TARNAME
+#undef PACKAGE_VERSION
+#undef PACKAGE_URL
+#include "octave/config.h"
+
+#include "octave/debug.h"
+#include "octave/octave.h"
+#include "octave/symtab.h"
+#include "octave/parse.h"
+#include "octave/unwind-prot.h"
+#include "octave/toplev.h"
+#include "octave/load-path.h"
+#include "octave/error.h"
+#include "octave/quit.h"
+#include "octave/variables.h"
+#include "octave/sighandlers.h"
+#include "octave/sysdep.h"
+#include "octave/str-vec.h"
+#include "octave/cmd-hist.h"
+#include "octave/cmd-edit.h"
+#include "octave/oct-env.h"
+#include "octave/symtab.h"
+#include "cmd-edit.h"
+
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+extern OCTINTERP_API YY_BUFFER_STATE create_buffer (FILE *f);
+extern OCTINTERP_API void switch_to_buffer (YY_BUFFER_STATE buf);
+extern OCTINTERP_API FILE *get_input_from_stdin (void);
+
+// System
+#include <termios.h>
+#include <sys/types.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <iostream>
+#include <vector>
+#include "pty.h"
+
+class OctaveMainThread;
+class OctaveCallbackThread;
+
+/**
+  * \class MainWindow
+  *
+  * Represents the main window.
+  */
+class MainWindow : public QMainWindow {
+    Q_OBJECT
+public:
+    MainWindow(QWidget *parent = 0);
+    ~MainWindow();
+
+    bool isRunning() { return m_isRunning; }
+    OctaveTerminal *octaveTerminal() { return m_octaveTerminalDockWidget->octaveTerminal(); }
+    VariablesDockWidget *variablesDockWidget() { return m_variablesDockWidget; }
+    HistoryDockWidget *historyDockWidget() { return m_historyDockWidget; }
+    FilesDockWidget *filesDockWidget() { return m_filesDockWidget; }
+
+public slots:
+    void handleOpenFileRequest(QString fileName);
+    void reportStatusMessage(QString statusMessage);
+    void handleSaveWorkspaceRequest();
+    void handleLoadWorkspaceRequest();
+    void handleClearWorkspaceRequest();
+    void handleCommandDoubleClicked(QString command);
+
+protected:
+    void closeEvent(QCloseEvent *closeEvent);
+    void readSettings();
+    void writeSettings();
+
+private:
+    void construct();
+    void establishOctaveLink();
+    OctaveTerminalDockWidget *m_octaveTerminalDockWidget;
+    VariablesDockWidget *m_variablesDockWidget;
+    HistoryDockWidget *m_historyDockWidget;
+    FilesDockWidget *m_filesDockWidget;    
+    BrowserDockWidget *m_browserDockWidget;
+    BrowserDockWidget *m_serviceDockWidget;
+
+    QStatusBar *m_statusBar;
+    QToolBar *m_generalPurposeToolbar;
+    QString m_settingsFile;
+
+    // Threads for running octave and managing the data interaction.
+    OctaveMainThread *m_octaveMainThread;
+    OctaveCallbackThread *m_octaveCallbackThread;
+    bool m_isRunning;
+};
+
+class OctaveMainThread : public QThread {
+    Q_OBJECT
+public:
+    OctaveMainThread(QObject *parent)
+        : QThread(parent) {
+    }
+protected:
+    void run() {
+        int argc = 3;
+        const char* argv[] = {"octave", "--interactive", "--line-editing"};
+        octave_main(argc, (char**)argv, 1);
+        main_loop();
+        clean_up_and_exit(0);
+    }
+};
+
+class OctaveCallbackThread : public QThread {
+    Q_OBJECT
+public:
+    OctaveCallbackThread(QObject *parent, MainWindow *mainWindow)
+        : QThread(parent),
+          m_mainWindow(mainWindow) {
+    }
+
+protected:
+    void run() {
+        while(m_mainWindow->isRunning()) {
+
+        // Get a full variable list.
+        QList<SymbolRecord> symbolTable = OctaveLink::instance()->currentSymbolTable();
+        if(symbolTable.size()) {
+            m_mainWindow->variablesDockWidget()->setVariablesList(symbolTable);
+        }
+
+        // Collect history list.
+        string_vector historyList = OctaveLink::instance()->currentHistory();
+        if(historyList.length()) {
+            m_mainWindow->historyDockWidget()->updateHistory(historyList);
+        }
+
+            usleep(100000);
+        }
+    }
+private:
+    MainWindow *m_mainWindow;
+};
+
+#endif // MAINWINDOW_H
new file mode 100644
--- /dev/null
+++ b/gui//src/NumberedCodeEdit.cpp
@@ -0,0 +1,591 @@
+/* This file is part of the KDE libraries
+    Copyright (C) 2005, 2006 KJSEmbed Authors
+    See included AUTHORS file.
+
+    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 <QTextDocument>
+#include <QTextBlock>
+#include <QHBoxLayout>
+#include <QScrollBar>
+#include <QPainter>
+#include <QAbstractTextDocumentLayout>
+#include <QToolTip>
+#include <QTextStream>
+#include <QProcess>
+#include <QRegExp>
+#include <QMessageBox>
+#include <QFileInfo>
+
+#include "NumberedCodeEdit.h"
+#include "config.h"
+
+NumberBar::NumberBar( QWidget *parent )
+    : QWidget( parent ), edit(0), currentLine(-1), bugLine(-1)
+{
+    // Make room for 4 digits and the breakpoint icon
+    setFixedWidth( fontMetrics().width( QString("0000") + 10 + 32 ) );
+    stopMarker = QPixmap();// QString(ICON_PATH) + "/stop.png" );
+    currentMarker = QPixmap();// QString(ICON_PATH) + "/bookmark.png" );
+    bugMarker = QPixmap();// QString(ICON_PATH) + "/bug.png" );
+}
+
+NumberBar::~NumberBar()
+{
+}
+
+void NumberBar::setCurrentLine( int lineno )
+{
+    currentLine = lineno;
+    update();
+}
+
+void NumberBar::setBugLine( int lineno )
+{
+    bugLine = lineno;
+}
+
+void NumberBar::toggleBreakpoint( int lineno )
+{
+  if(lineno > 0)
+  {
+    int i = breakpoints.indexOf(lineno);
+
+    if(i > -1)
+      breakpoints.removeAt(i);
+    else
+      breakpoints.push_back(lineno);
+  }
+  update();
+}
+
+void NumberBar::setTextEdit( SimpleEditor *edit )
+{
+    this->edit = edit;
+    setFixedWidth( edit->fontMetrics().width( QString("0000") + 10 + 32 ) );
+    connect( edit->document()->documentLayout(), SIGNAL( update(const QRectF &) ),
+	     this, SLOT( update() ) );
+    connect( edit->verticalScrollBar(), SIGNAL(valueChanged(int) ),
+	     this, SLOT( update() ) );
+}
+
+void NumberBar::paintEvent( QPaintEvent * )
+{
+    QVector<qreal> lines_list;
+    int first_line_no;
+    edit->publicBlockBoundingRectList(lines_list, first_line_no);
+    
+    const QFontMetrics fm = edit->fontMetrics();
+    const int ascent = fontMetrics().ascent(); // height = ascent + descent
+   
+    QPainter p(this);
+    p.setPen(palette().windowText().color());
+    
+    bugRect = QRect();
+    stopRect = QRect();
+    currentRect = QRect();
+    
+    int position_y;
+    int lineCount;
+    
+    const int lines_list_size=lines_list.size();
+    
+    for(int i=0;i<lines_list_size;i++)
+    {
+    	position_y=qRound( lines_list[i] );
+    	lineCount=first_line_no+i;
+    	
+    	const QString txt = QString::number( lineCount );
+        p.drawText( width() - fm.width(txt)- 2, position_y+ascent, txt );
+        
+        // Bug marker
+	if ( bugLine == lineCount ) {
+	    p.drawPixmap( 1, position_y, bugMarker );
+	    bugRect = QRect( 19, position_y, bugMarker.width(), bugMarker.height() );
+	}
+	
+	// Stop marker
+	if ( breakpoints.contains(lineCount) ) {
+	    p.drawPixmap( 1, position_y, stopMarker );
+	    stopRect = QRect( 1, position_y,stopMarker.width(),  stopMarker.height() );
+	}
+	
+	// Current line marker
+	if ( currentLine == lineCount ) {
+	    p.drawPixmap( 1, position_y, currentMarker );
+	    currentRect = QRect( 1, position_y, currentMarker.width(), currentMarker.height() );
+	}
+    }
+    
+    /*
+    
+    int contentsY = edit->verticalScrollBar()->value();
+    qreal pageBottom = contentsY + edit->viewport()->height();
+    const QFontMetrics fm = fontMetrics();
+    const int ascent = fontMetrics().ascent() + 1; // height = ascent + descent + 1
+    int lineCount = 1;
+
+    QPainter p(this);
+    p.setPen(palette().windowText().color());
+
+    bugRect = QRect();
+    stopRect = QRect();
+    currentRect = QRect();
+
+    for ( QTextBlock block = edit->document()->begin();
+	  block.isValid(); block = block.next(), ++lineCount ) {
+
+        const QRectF boundingRect = edit->publicBlockBoundingRect( block );
+
+        QPointF position = boundingRect.topLeft();
+        if ( position.y() + boundingRect.height() < contentsY )
+            continue;
+        if ( position.y() > pageBottom )
+            break;
+
+        const QString txt = QString::number( lineCount );
+        p.drawText( width() - fm.width(txt), qRound( position.y() ) - contentsY + ascent, txt );
+
+	// Bug marker
+	if ( bugLine == lineCount ) {
+	    p.drawPixmap( 1, qRound( position.y() ) - contentsY, bugMarker );
+	    bugRect = QRect( 1, qRound( position.y() ) - contentsY, bugMarker.width(), bugMarker.height() );
+	}
+
+	// Stop marker
+	if ( breakpoints.contains(lineCount) ) {
+	    p.drawPixmap( 19, qRound( position.y() ) - contentsY, stopMarker );
+	    stopRect = QRect( 19, qRound( position.y() ) - contentsY, stopMarker.width(), stopMarker.height() );
+	}
+
+	// Current line marker
+	if ( currentLine == lineCount ) {
+	    p.drawPixmap( 19, qRound( position.y() ) - contentsY, currentMarker );
+	    currentRect = QRect( 19, qRound( position.y() ) - contentsY, currentMarker.width(), currentMarker.height() );
+	}
+    }
+    */
+}
+
+bool NumberBar::event( QEvent *event )
+{
+    if ( event->type() == QEvent::ToolTip ) {
+	QHelpEvent *helpEvent = static_cast<QHelpEvent *>(event);
+
+	if ( stopRect.contains( helpEvent->pos() ) ) {
+	    QToolTip::showText( helpEvent->globalPos(), tr("Stop Here"));
+	}
+	else if ( currentRect.contains( helpEvent->pos() ) ) {
+	    QToolTip::showText( helpEvent->globalPos(), tr("Current Line"));
+	}
+	else if ( bugRect.contains( helpEvent->pos() ) ) {
+	    QToolTip::showText( helpEvent->globalPos(), tr("Error Line" ));
+	}
+    }
+
+    return QWidget::event(event);
+}
+
+QList<int> *NumberBar::getBreakpoints()
+{
+  return &breakpoints;
+}
+
+
+
+NumberedCodeEdit::NumberedCodeEdit( QWidget *parent, SimpleEditor *textEdit )
+    : QFrame( parent )
+{
+	setFrameStyle( QFrame::StyledPanel | QFrame::Sunken );
+	setLineWidth( 2 );
+	
+	view=textEdit;
+        view->installEventFilter( this );
+	
+	connect( view->document(), SIGNAL(contentsChange(int,int,int)), this, SLOT(textChanged(int,int,int)) );
+	
+	connect( view, SIGNAL(cursorPositionChanged()), this, SLOT(cursor_moved_cb()) );
+	
+	// Setup the line number pane
+	
+	numbers = new NumberBar( this );
+	numbers->setTextEdit( view );
+	//numbers=NULL;
+	
+	
+	vbox = new QVBoxLayout(this);
+	vbox->setSpacing( 0 );
+	vbox->setMargin( 0 );
+	
+	hbox = new QHBoxLayout;
+	vbox->addLayout(hbox);
+	
+	hbox->setSpacing( 0 );
+	hbox->setMargin( 0 );
+	hbox->addWidget( numbers );
+	hbox->addWidget( view );
+
+	textModifiedOk=false;
+	
+	QHBoxLayout *messages_layout= new QHBoxLayout;
+	vbox->addLayout(messages_layout);
+	messages_layout->setSpacing( 0 );
+	messages_layout->setMargin( 0 );
+	}
+
+
+NumberedCodeEdit::~NumberedCodeEdit()
+{
+	hide();
+	//printf("Borrado ntv\n");
+}
+
+void NumberedCodeEdit::setCurrentLine( int lineno )
+{
+	currentLine = lineno;
+	if(numbers!=NULL) numbers->setCurrentLine( lineno );
+	
+	//Move cursor to lineno
+	if(lineno>-1)
+	{
+		QTextCursor cursor=textEdit()->textCursor();
+		
+		cursor.movePosition(QTextCursor::Start);
+		
+		for(int i=1;i<lineno;i++)
+			cursor.movePosition(QTextCursor::NextBlock);
+		
+		textEdit()->setTextCursor(cursor);
+	}
+	
+	textChanged( 0, 0, 1 );
+}
+
+void NumberedCodeEdit::toggleBreakpoint( int lineno )
+{
+	if(numbers!=NULL) numbers->toggleBreakpoint( lineno );
+}
+
+void NumberedCodeEdit::setBugLine( int lineno )
+{
+	if(numbers!=NULL) numbers->setBugLine( lineno );
+}
+
+void NumberedCodeEdit::textChanged( int /*pos*/, int removed, int added )
+{
+    //Q_UNUSED( pos );
+
+    if ( removed == 0 && added == 0 )
+	return;
+
+    //QTextBlock block = highlight.block();
+    //QTextBlock block = view->document()->begin();
+    //QTextBlockFormat fmt = block.blockFormat();
+    //QColor bg = view->palette().base().color();
+    //fmt.setBackground( bg );
+    //highlight.setBlockFormat( fmt );
+    /*
+    QTextBlockFormat fmt;
+
+    int lineCount = 1;
+    for ( QTextBlock block = view->document()->begin();
+	  block.isValid() && block!=view->document()->end(); block = block.next(), ++lineCount ) {
+
+	if ( lineCount == currentLine )
+	{
+	    fmt = block.blockFormat();
+	    QColor bg = view->palette().highlight().color();
+	    fmt.setBackground( bg );
+
+	    highlight = QTextCursor( block );
+	    highlight.movePosition( QTextCursor::EndOfBlock, QTextCursor::KeepAnchor );
+	    highlight.setBlockFormat( fmt );
+
+	    break;
+	}
+    }
+    */
+    
+    if( !textModifiedOk && view->document()->isModified() )
+    {
+    	textModifiedOk=true;
+    	emit textModified();
+    }
+}
+
+bool NumberedCodeEdit::eventFilter( QObject *obj, QEvent *event )
+{
+    if ( obj != view )
+	return QFrame::eventFilter(obj, event);
+
+    if ( event->type() == QEvent::ToolTip ) {
+	QHelpEvent *helpEvent = static_cast<QHelpEvent *>(event);
+
+	QTextCursor cursor = view->cursorForPosition( helpEvent->pos() );
+	cursor.movePosition( QTextCursor::StartOfWord, QTextCursor::MoveAnchor );
+	cursor.movePosition( QTextCursor::EndOfWord, QTextCursor::KeepAnchor );
+
+	QString word = cursor.selectedText();
+	emit mouseHover( word );
+	emit mouseHover( helpEvent->pos(), word );
+
+	// QToolTip::showText( helpEvent->globalPos(), word ); // For testing
+    }
+
+    return false;
+}
+
+QList<int> *NumberedCodeEdit::getBreakpoints()
+{
+	QList<int> *br=NULL;
+	if(numbers!=NULL) br=numbers->getBreakpoints();
+	return br;
+}
+
+void NumberedCodeEdit::open(QString path)
+{
+  FILE *fl;
+
+  fl = fopen(path.toLocal8Bit().constData(), "rt");
+  if(fl)
+  {
+	fclose(fl);
+	filePath = path;
+	
+	textEdit()->load(path);
+	
+	textModifiedOk=false;
+	textEdit()->document()->setModified(false);
+  }else{
+    throw path;
+  }
+}
+
+bool NumberedCodeEdit::save(QString path)
+{
+  FILE *fl;
+
+  if(path.isEmpty()) path = filePath;
+  QRegExp re("[A-Za-z_][A-Za-z0-9_]*\\.m");
+  
+  if( ! re.exactMatch( QFileInfo(path).fileName() ) )
+  {
+	QMessageBox msgBox;
+	msgBox.setText( tr("This file name is not valid.") );
+	msgBox.setInformativeText(tr("Octave doesn't understand this file name:\n")+path+tr("\nPlease, change it.\n Do you want to save your changes?"));
+	msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Cancel);
+	msgBox.setDefaultButton(QMessageBox::Save);
+	int ret = msgBox.exec();
+	switch (ret)
+	{
+		case QMessageBox::Save:
+		    // Save was clicked
+		    break;
+		case QMessageBox::Cancel:
+		    // Cancel was clicked
+		    	return false;
+		    break;
+		default:
+		    // should never be reached
+		    break;
+	}
+  }
+  
+  
+  fl = fopen(path.toLocal8Bit().constData(), "wt");
+  if(fl)
+  {
+    filePath = path;
+    QTextStream *stream = new QTextStream(fl);
+    (*stream) << textEdit()->document()->toPlainText();
+    delete stream;
+    fclose(fl);
+    textModifiedOk=false;
+    view->document()->setModified(false);
+  }else{
+    return false;
+  }
+  
+  return true;
+}
+
+QString NumberedCodeEdit::path()
+{
+  return filePath;
+}
+
+void NumberedCodeEdit::setPath(QString path)
+{
+	filePath=path;
+	textEdit()->setFile(path);
+}
+
+void NumberedCodeEdit::setModified(bool modify)
+{
+	textModifiedOk=modify;
+}
+
+bool NumberedCodeEdit::modified()
+{
+	return textModifiedOk;
+}
+
+void NumberedCodeEdit::cursor_moved_cb()
+{
+	QTextCursor cursor=view->textCursor();
+	QTextBlock actual_block=cursor.block();
+	int lineCount=1;
+	QTextBlock block = view->document()->begin();
+	
+	for ( ;block.isValid() && actual_block!=block; block = block.next()) lineCount++ ;
+}
+
+static QString startLineInsertText(QString str, QString textToInsert)
+{
+	str.replace(QChar(0x2029), "\n");
+	//printf("str=%s\n", str.toLocal8Bit().data() );
+	
+	QStringList list = str.split("\n");
+	
+	for(int i=0;i<list.size();i++)
+	{
+		QString s=list[i];
+		
+		int x;
+		
+		for(x=0;x<s.size();x++)
+		{
+			if( s.at(x)!=' ' && s.at(x)!='\t' ) break;
+		}
+		
+		QString s1=s.left(x);
+                QString s2=s.right(s.size()-x);
+		list[i]=s1+textToInsert+s2;
+	}
+	
+	return list.join("\n");
+}
+
+static QString startLineRemoveText(QString str, QStringList textToRemove)
+{
+	str.replace(QChar(0x2029), "\n");
+	
+	QStringList list = str.split("\n");
+	
+	for(int i=0;i<list.size();i++)
+	{
+		QString s=list[i];
+		
+		int x;
+		
+		for(x=0;x<s.size();x++)
+		{
+			if( s.at(x)!=' ' && s.at(x)!='\t' ) break;
+		}
+		
+		QString s1=s.left(x);
+		QString s2=s.right(s.size()-x);
+		
+		for(int k=0;k<textToRemove.size();k++)
+		{
+			if(s1.endsWith(textToRemove[k]))
+			{
+				s1=s1.left(s1.size()-textToRemove[k].size());
+				break;
+			}
+			else if(s2.startsWith(textToRemove[k]))
+			{
+				s2=s2.right(s2.size()-textToRemove[k].size());
+				break;
+			}
+		}
+		
+		//printf("s1=%s s2=%s \n", s1.toLocal8Bit().data(), s2.toLocal8Bit().data());
+		list[i]=s1+s2;
+	}
+	
+	return list.join("\n");
+}
+
+void NumberedCodeEdit::indent()
+{
+	QTextCursor cursor(textEdit()->textCursor());
+	
+	if( !cursor.hasSelection() ) return;
+	
+	QString str=cursor.selectedText();
+	
+	str=startLineInsertText(str, "\t");
+	
+	cursor.insertText(str);
+	cursor.setPosition(cursor.position()-str.size(), QTextCursor::KeepAnchor);
+	textEdit()->setTextCursor(cursor);
+}
+
+void NumberedCodeEdit::unindent()
+{
+	//QTextDocument *doc=textEdit()->document();
+	
+	QTextCursor cursor(textEdit()->textCursor());
+	
+	if( !cursor.hasSelection() ) return;
+	
+	QString str=cursor.selectedText();
+	
+	QStringList textToRemove;
+	textToRemove << "\t" << " ";
+	str=startLineRemoveText(str, textToRemove);
+	
+	cursor.insertText(str);
+	cursor.setPosition(cursor.position()-str.size(), QTextCursor::KeepAnchor);
+	textEdit()->setTextCursor(cursor);
+}
+
+void NumberedCodeEdit::comment()
+{
+	//QTextDocument *doc=textEdit()->document();
+	
+	QTextCursor cursor(textEdit()->textCursor());
+	
+	if( !cursor.hasSelection() ) return;
+	
+	QString str=cursor.selectedText();
+	
+	str=startLineInsertText(str, "%");
+	
+	cursor.insertText(str);
+	cursor.setPosition(cursor.position()-str.size(), QTextCursor::KeepAnchor);
+	textEdit()->setTextCursor(cursor);
+}
+
+void NumberedCodeEdit::uncomment()
+{
+	//QTextDocument *doc=textEdit()->document();
+	
+	QTextCursor cursor(textEdit()->textCursor());
+	
+	if( !cursor.hasSelection() ) return;
+	
+	QString str=cursor.selectedText();
+	
+	QStringList textToRemove;
+	textToRemove << "%" << "#";
+	str=startLineRemoveText(str, textToRemove);
+	
+	cursor.insertText(str);
+	cursor.setPosition(cursor.position()-str.size(), QTextCursor::KeepAnchor);
+	textEdit()->setTextCursor(cursor);
+}
new file mode 100644
--- /dev/null
+++ b/gui//src/NumberedCodeEdit.h
@@ -0,0 +1,169 @@
+/* This file is part of the KDE libraries
+    Copyright (C) 2005, 2006 KJSEmbed Authors
+    See included AUTHORS file.
+
+    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.
+*/
+// -*- c++ -*-
+#ifndef NUMBERED_TEXT_VIEW_H
+#define NUMBERED_TEXT_VIEW_H
+
+#include <QFrame>
+#include <QPixmap>
+#include <QTextCursor>
+#include <QLabel>
+#include <QVBoxLayout>
+#include <QHBoxLayout>
+#include "SimpleEditor.h"
+
+class SimpleEditor;
+class QHBoxLayout;
+
+/**
+ * @internal Used to display the numbers.
+ */
+class NumberBar : public QWidget
+{
+    Q_OBJECT
+
+public:
+    NumberBar( QWidget *parent );
+    ~NumberBar();
+
+    void setCurrentLine( int lineno );
+    void setBugLine( int lineno );
+    void toggleBreakpoint( int lineno );
+    QList<int> *getBreakpoints();
+
+    void setTextEdit( SimpleEditor *edit );
+    void paintEvent( QPaintEvent *ev );
+
+protected:
+    bool event( QEvent *ev );
+
+private:
+    SimpleEditor *edit;
+    QPixmap stopMarker;
+    QPixmap currentMarker;
+    QPixmap bugMarker;
+    QList<int> breakpoints;
+    int currentLine;
+    int bugLine;
+    QRect stopRect;
+    QRect currentRect;
+    QRect bugRect;
+};
+
+/**
+ * Displays a CodeEdit with line numbers.
+ */
+class NumberedCodeEdit : public QFrame
+{
+    Q_OBJECT
+
+public:
+    NumberedCodeEdit( QWidget *parent = 0 , SimpleEditor *textEdit=new SimpleEditor() );
+    ~NumberedCodeEdit();
+
+    QList<int> *getBreakpoints();
+
+    void open(QString path);
+    
+    /**Saves file to path. @return true if all is OK.*/
+    bool save(QString path = QString());
+
+    QString path();
+    void setPath(QString path);
+    
+    bool modified();
+    void setModified(bool modify);
+
+    /** Returns the CodeEdit of the main view. */
+    SimpleEditor *textEdit() const { return view; }
+
+    /**
+     * Sets the line that should have the current line indicator.
+     * A value of -1 indicates no line should show the indicator.
+     */
+    void setCurrentLine( int lineno );
+
+    /**
+     * Toggle breakpoint
+     */
+    void toggleBreakpoint( int lineno );
+
+    /**
+     * Sets the line that should have the bug line indicator.
+     * A value of -1 indicates no line should show the indicator.
+     */
+    void setBugLine( int lineno );
+
+    /** @internal Used to get tooltip events from the view for the hover signal. */
+    bool eventFilter( QObject *obj, QEvent *event );
+    
+    /**Indent selected text.*/
+    void indent();
+    
+    /**UnIndent selected text.*/
+    void unindent();
+    
+    /**Comment selected text.*/
+    void comment();
+    
+    /**UnComment selected text.*/
+    void uncomment();
+
+signals:
+    /**
+     * Emitted when the mouse is hovered over the text edit component.
+     * @param word The word under the mouse pointer
+     */
+    void mouseHover( const QString &word );
+
+    /**
+     * Emitted when the mouse is hovered over the text edit component.
+     * @param pos The position of the mouse pointer.
+     * @param word The word under the mouse pointer
+     */
+    void mouseHover( const QPoint &pos, const QString &word );
+    
+    /**
+     * Emitted when file is changed.
+     */
+    void textModified();
+
+protected slots:
+    /** @internal Used to update the highlight on the current line. */
+    void textChanged( int pos, int added, int removed );
+public slots:
+    void cursor_moved_cb();
+
+private:
+    QString filePath;
+    QLabel *line_column_label;
+    SimpleEditor *view;
+    NumberBar *numbers;
+    QHBoxLayout *hbox;
+    QVBoxLayout *vbox;
+    int currentLine;
+    QTextCursor highlight;
+    bool textModifiedOk;
+};
+
+
+#endif // NUMBERED_TEXT_VIEW_H
+
+
new file mode 100644
--- /dev/null
+++ b/gui//src/OctaveLink.cpp
@@ -0,0 +1,132 @@
+/*
+
+Copyright (C) 2007,2008,2009 John P. Swensen
+
+Octave 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, or (at your option) any
+later version.
+
+Octave 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 Octave; see the file COPYING.  If not, write to the Free
+Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.
+
+*/
+
+// Born July 13, 2007.
+
+#include "OctaveLink.h"
+
+OctaveLink OctaveLink::m_singleton;
+
+
+OctaveLink::OctaveLink()
+    : QObject(),
+      m_previousHistoryLength(0) {
+    m_symbolTableSemaphore = new QSemaphore(1);
+    m_historySemaphore = new QSemaphore(1);
+}
+
+OctaveLink::~OctaveLink() {
+}
+
+int OctaveLink::readlineEventHook() {
+  OctaveLink::instance()->processOctaveServerData();
+  return 0;
+}
+
+QString OctaveLink::octaveValueAsQString(OctaveValue octaveValue) {
+    // Convert single qouted string.
+    if(octaveValue.is_sq_string()) {
+        return QString("\'%1\'").arg(octaveValue.string_value().c_str());
+
+    // Convert double qouted string.
+    } else if(octaveValue.is_dq_string()) {
+        return QString("\"%1\"").arg(octaveValue.string_value().c_str());
+
+    // Convert real scalar.
+    } else if(octaveValue.is_real_scalar()) {
+        return QString("%1").arg(octaveValue.scalar_value());
+
+    // Convert complex scalar.
+    } else if(octaveValue.is_complex_scalar()) {
+        return QString("%1 + %2i").arg(octaveValue.scalar_value()).arg(octaveValue.complex_value().imag());
+
+    // Convert range.
+    } else if(octaveValue.is_range()) {
+        return QString("%1 : %2 : %3").arg(octaveValue.range_value().base())
+                                      .arg(octaveValue.range_value().inc())
+                                      .arg(octaveValue.range_value().limit());
+
+    // Convert real matrix.
+    } else if(octaveValue.is_real_matrix()) {
+        // TODO: Convert real matrix into a string.
+        return QString("{matrix}");
+
+    // Convert complex matrix.
+    } else if(octaveValue.is_complex_matrix()) {
+        // TODO: Convert complex matrix into a string.
+        return QString("{complex matrix}");
+
+    // If everything else does not fit, we could not recognize the type.
+    } else {
+        return QString("<Type not recognized>");
+    }
+}
+
+void OctaveLink::fetchSymbolTable() {
+    m_symbolTableSemaphore->acquire();
+    m_symbolTableBuffer.clear();
+    std::list<SymbolRecord> allVariables = symbol_table::all_variables();
+    std::list<SymbolRecord>::iterator iterator;
+    for(iterator = allVariables.begin(); iterator != allVariables.end(); iterator++)
+        m_symbolTableBuffer.append(*iterator);
+    m_symbolTableSemaphore->release();
+    emit symbolTableChanged();
+}
+
+
+void OctaveLink::fetchHistory() {
+    int currentLen = command_history::length();
+    if(currentLen != m_previousHistoryLength) {
+        m_historySemaphore->acquire();
+        for(int i = m_previousHistoryLength; i < currentLen; i++) {
+            m_historyBuffer.append(command_history::get_entry(i));
+        }
+        m_historySemaphore->release();
+        m_previousHistoryLength = currentLen;
+        emit historyChanged();
+    }
+}
+
+QList<SymbolRecord> OctaveLink::currentSymbolTable() {
+    QList<SymbolRecord> m_symbolTableCopy;
+
+    // Generate a deep copy of the current symbol table.
+    m_symbolTableSemaphore->acquire();
+    foreach(SymbolRecord symbolRecord, m_symbolTableBuffer)
+        m_symbolTableCopy.append(symbolRecord);
+    m_symbolTableSemaphore->release();
+
+    return m_symbolTableCopy;
+}
+
+string_vector OctaveLink::currentHistory() {
+    m_historySemaphore->acquire();
+    string_vector retval(m_historyBuffer);
+    m_historyBuffer = string_vector();
+    m_historySemaphore->release();
+    return retval;
+}
+
+void OctaveLink::processOctaveServerData() {
+    fetchSymbolTable();
+    fetchHistory();
+}
+
new file mode 100644
--- /dev/null
+++ b/gui//src/OctaveLink.h
@@ -0,0 +1,139 @@
+/*
+ *
+ * Copyright (C) 2007, 2008, 2009 John P. Swensen
+ *
+ * This file is as a part of OctaveDE.
+ *
+ * Octave 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, or (at your option) any
+ * later version.
+ *
+ * Octave 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 Octave; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * */
+#ifndef OCTAVELINK_H
+#define OCTAVELINK_H
+
+// Octave includes
+#undef PACKAGE_BUGREPORT
+#undef PACKAGE_NAME
+#undef PACKAGE_STRING
+#undef PACKAGE_TARNAME
+#undef PACKAGE_VERSION
+#undef PACKAGE_URL
+#include <octave/config.h>
+#include "octave/cmd-edit.h"
+#include "octave/error.h"
+#include "octave/file-io.h"
+#include "octave/input.h"
+#include "octave/lex.h"
+#include "octave/load-path.h"
+#include "octave/octave.h"
+#include "octave/oct-hist.h"
+#include "octave/oct-map.h"
+#include "octave/oct-obj.h"
+#include "octave/ops.h"
+#include "octave/ov.h"
+#include "octave/ov-usr-fcn.h"
+#include "octave/symtab.h"
+#include "octave/pt.h"
+#include "octave/pt-eval.h"
+#include "octave/config.h"
+#include "octave/Range.h"
+#include "octave/toplev.h"
+#include "octave/procstream.h"
+#include "octave/sighandlers.h"
+#include "octave/debug.h"
+#include "octave/sysdep.h"
+#include "octave/ov.h"
+#include "octave/unwind-prot.h"
+#include "octave/utils.h"
+#include "octave/variables.h"
+
+// Standard includes
+#include <iostream>
+#include <string>
+#include <vector>
+#include <readline/readline.h>
+
+// Qt includes
+#include <QMutexLocker>
+#include <QMutex>
+#include <QFileInfo>
+#include <QList>
+#include <QString>
+#include <QVector>
+#include <QSemaphore>
+#include <QObject>
+
+typedef symbol_table::symbol_record SymbolRecord;
+typedef octave_value OctaveValue;
+
+/**
+  * \class OctaveLink
+  * Manages a link to an octave instance.
+  */
+class OctaveLink : QObject
+{
+    Q_OBJECT
+public:
+    static OctaveLink *instance() { return &m_singleton; }
+    static int readlineEventHook(void);
+    static QString octaveValueAsQString(OctaveValue octaveValue);
+
+    /**
+      * Returns a copy of the current symbol table buffer.
+      * \return Copy of the current symbol table buffer.
+      */
+    QList<SymbolRecord> currentSymbolTable();
+
+    /**
+      * Returns a copy of the current history buffer.
+      * \return Copy of the current history buffer.
+      */
+    string_vector currentHistory();
+
+    void processOctaveServerData();
+
+    /**
+      * Updates the current symbol table with new data
+      * from octave.
+      */
+    void fetchSymbolTable();
+
+    /**
+      * Updates the current history buffer with new data
+      * from octave.
+      */
+    void fetchHistory();
+
+signals:
+    void symbolTableChanged();
+    void historyChanged();
+
+private:
+    OctaveLink();
+    ~OctaveLink();
+
+    /** Variable related member variables. */
+    QSemaphore *m_symbolTableSemaphore;
+    QList<SymbolRecord> m_symbolTableBuffer;
+
+    /** History related member variables. */
+    QSemaphore *m_historySemaphore;
+    string_vector m_historyBuffer;
+    int m_previousHistoryLength;
+
+    static OctaveLink m_singleton;
+};
+#endif // OCTAVELINK_H
+
new file mode 100644
--- /dev/null
+++ b/gui//src/OctaveTerminal.cpp
@@ -0,0 +1,52 @@
+/* Quint - A graphical user interface for Octave
+ * Copyright (C) 2011 Jacob Dawid
+ * jacob.dawid@googlemail.com
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "OctaveTerminal.h"
+#include <QHBoxLayout>
+#include <QVBoxLayout>
+#include <QStringListModel>
+#include <QStringList>
+
+OctaveTerminalDockWidget::OctaveTerminalDockWidget(QWidget *parent, OctaveTerminal *octaveTerminal)
+    : QDockWidget(parent) {
+    setObjectName("OctaveTerminalDockWidget");
+    setWindowTitle(tr("Octave terminal"));
+    m_octaveTerminal = octaveTerminal;
+    setWidget(m_octaveTerminal);
+}
+
+OctaveTerminalDockWidget::~OctaveTerminalDockWidget() {
+}
+
+OctaveTerminal *OctaveTerminalDockWidget::octaveTerminal() {
+    return m_octaveTerminal;
+}
+
+OctaveTerminal::OctaveTerminal(QWidget *parent)
+    : QTerminalWidget(0, parent) {
+    construct();
+}
+
+OctaveTerminal::~OctaveTerminal() {
+}
+
+void OctaveTerminal::construct() {
+    setScrollBarPosition(QTerminalWidget::ScrollBarRight);
+    setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+}
+
new file mode 100644
--- /dev/null
+++ b/gui//src/OctaveTerminal.h
@@ -0,0 +1,46 @@
+/* Quint - A graphical user interface for Octave
+ * Copyright (C) 2011 Jacob Dawid
+ * jacob.dawid@googlemail.com
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef OCTAVETERMINAL_H
+#define OCTAVETERMINAL_H
+
+#include "QTerminalWidget.h"
+#include <QDockWidget>
+
+class OctaveTerminal;
+class OctaveTerminalDockWidget : public QDockWidget {
+public:
+    OctaveTerminalDockWidget(QWidget *parent, OctaveTerminal *octaveTerminal);
+    ~OctaveTerminalDockWidget();
+
+    OctaveTerminal *octaveTerminal();
+
+private:
+    OctaveTerminal *m_octaveTerminal;
+};
+
+class OctaveTerminal : public QTerminalWidget {
+    Q_OBJECT
+public:
+    OctaveTerminal(QWidget *parent = 0);
+    ~OctaveTerminal();
+
+private:
+    void construct();
+};
+#endif // OCTAVETERMINAL_H
new file mode 100644
--- /dev/null
+++ b/gui//src/ProcessInfo.cpp
@@ -0,0 +1,1054 @@
+/*
+    Copyright 2007-2008 by Robert Knight <robertknight@gmail.countm>
+
+    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 "ProcessInfo.h"
+
+// Unix
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#include <pwd.h>
+
+// Qt
+#include <QtCore/QDir>
+#include <QtCore/QFileInfo>
+#include <QtCore/QRegExp>
+#include <QtCore/QTextStream>
+#include <QtCore/QStringList>
+#include <QtCore/QSet>
+
+// KDE
+#include "konsole_export.h"
+
+#if defined(Q_OS_MAC)
+#include <sys/sysctl.h>
+#include <libproc.h>
+#ifdef HAVE_SYS_PROC_INFO_H
+#include <sys/proc_info.h>
+#endif
+#ifdef HAVE_SYS_PROC_H
+#include <sys/proc.h>
+#endif
+//#include <kde_file.h>
+#define KDE_struct_stat struct stat
+#define KDE_stat ::stat
+#endif
+
+#if defined(Q_OS_FREEBSD)
+#include <sys/sysctl.h> //krazy:exclude=includes
+#include <sys/types.h>
+#include <sys/user.h>
+#include <sys/syslimits.h>
+#include <libutil.h>
+#endif
+
+ProcessInfo::ProcessInfo(int pid , bool enableEnvironmentRead)
+    : _fields( ARGUMENTS | ENVIRONMENT ) // arguments and environments
+                                         // are currently always valid,
+                                         // they just return an empty
+                                         // vector / map respectively
+                                         // if no arguments
+                                         // or environment bindings
+                                         // have been explicitly set
+    , _enableEnvironmentRead(enableEnvironmentRead)
+    , _pid(pid)
+    , _parentPid(0)
+    , _foregroundPid(0)
+    , _userId(0)
+    , _lastError(NoError)
+    , _userName(QString())
+    , _userHomeDir(QString())
+{
+}
+
+ProcessInfo::Error ProcessInfo::error() const { return _lastError; }
+void ProcessInfo::setError(Error error) { _lastError = error; }
+
+void ProcessInfo::update() 
+{
+    readProcessInfo(_pid,_enableEnvironmentRead);
+}
+
+QString ProcessInfo::validCurrentDir() const
+{
+   bool ok = false;
+
+   // read current dir, if an error occurs try the parent as the next
+   // best option
+   int currentPid = parentPid(&ok);
+   QString dir = currentDir(&ok);
+   while ( !ok && currentPid != 0 )
+   {
+       ProcessInfo* current = ProcessInfo::newInstance(currentPid);
+       current->update();
+       currentPid = current->parentPid(&ok); 
+       dir = current->currentDir(&ok);
+       delete current;
+   }
+
+   return dir;
+}
+
+QString ProcessInfo::format(const QString& input) const
+{
+   bool ok = false;
+
+   QString output(input);
+
+   // search for and replace known marker
+   output.replace("%u",userName());
+   output.replace("%n",name(&ok));
+   output.replace("%c",formatCommand(name(&ok),arguments(&ok),ShortCommandFormat));
+   output.replace("%C",formatCommand(name(&ok),arguments(&ok),LongCommandFormat));
+   
+   QString dir = validCurrentDir();
+   if (output.contains("%D"))
+   {
+      QString homeDir = userHomeDir();
+      QString tempDir = dir;
+      // Change User's Home Dir w/ ~ only at the beginning
+      if (tempDir.startsWith(homeDir))
+      {
+         tempDir.remove(0, homeDir.length());
+         tempDir.prepend('~');
+      }
+      output.replace("%D", tempDir);
+   }
+   output.replace("%d", dir);
+   
+   // remove any remaining %[LETTER] sequences
+   // output.replace(QRegExp("%\\w"), QString());
+
+   return output;
+}
+
+QString ProcessInfo::formatCommand(const QString& name, 
+                                   const QVector<QString>& arguments,
+                                   CommandFormat format) const
+{
+    Q_UNUSED(name);
+    Q_UNUSED(format);
+
+    // TODO Implement me
+    return QStringList(QList<QString>::fromVector(arguments)).join(" ");
+}
+
+QVector<QString> ProcessInfo::arguments(bool* ok) const
+{
+    *ok = _fields & ARGUMENTS;
+
+    return _arguments;
+}
+
+QMap<QString,QString> ProcessInfo::environment(bool* ok) const
+{
+    *ok = _fields & ENVIRONMENT;
+
+    return _environment;
+}
+
+bool ProcessInfo::isValid() const
+{
+    return _fields & PROCESS_ID;
+}
+
+int ProcessInfo::pid(bool* ok) const
+{
+    *ok = _fields & PROCESS_ID;
+
+    return _pid;
+}
+
+int ProcessInfo::parentPid(bool* ok) const
+{
+    *ok = _fields & PARENT_PID;
+
+    return _parentPid;
+}
+
+int ProcessInfo::foregroundPid(bool* ok) const
+{
+    *ok = _fields & FOREGROUND_PID;
+
+    return _foregroundPid;
+}
+
+QString ProcessInfo::name(bool* ok) const
+{
+    *ok = _fields & NAME;
+
+    return _name;
+}
+
+int ProcessInfo::userId(bool* ok) const
+{
+    *ok = _fields & UID;
+
+    return _userId;
+}
+
+QString ProcessInfo::userName() const
+{
+    return _userName;
+}
+
+QString ProcessInfo::userHomeDir() const
+{
+    return _userHomeDir;
+}
+
+void ProcessInfo::setPid(int pid)
+{
+    _pid = pid;
+    _fields |= PROCESS_ID;
+}
+
+void ProcessInfo::setUserId(int uid)
+{
+    _userId = uid;
+    _fields |= UID;
+}
+
+void ProcessInfo::setUserName(const QString& name)
+{
+    _userName = name;
+    setUserHomeDir();
+}
+
+void ProcessInfo::setUserHomeDir()
+{
+    QString usersName = userName();
+    // JPS: I don't know a good QT replacement
+    //if (!usersName.isEmpty())
+    //    _userHomeDir = KUser(usersName).homeDir();
+    //else
+        _userHomeDir = QDir::homePath();
+}
+
+void ProcessInfo::setParentPid(int pid)
+{
+    _parentPid = pid;
+    _fields |= PARENT_PID;
+}
+void ProcessInfo::setForegroundPid(int pid)
+{
+    _foregroundPid = pid;
+    _fields |= FOREGROUND_PID;
+}
+
+QString ProcessInfo::currentDir(bool* ok) const
+{
+    if (ok)
+        *ok = _fields & CURRENT_DIR;
+
+    return _currentDir;
+}
+void ProcessInfo::setCurrentDir(const QString& dir)
+{
+    _fields |= CURRENT_DIR;
+    _currentDir = dir;
+}
+
+void ProcessInfo::setName(const QString& name)
+{
+    _name = name;
+    _fields |= NAME;
+}
+void ProcessInfo::addArgument(const QString& argument)
+{
+    _arguments << argument;    
+}
+
+void ProcessInfo::addEnvironmentBinding(const QString& name , const QString& value)
+{
+    _environment.insert(name,value);
+}
+
+void ProcessInfo::setFileError( QFile::FileError error )
+{
+    switch ( error )
+    {
+        case PermissionsError:
+            setError( PermissionsError );
+            break;
+        case NoError:
+            setError( NoError );
+            break;
+        default:
+            setError( UnknownError );
+    }
+}
+
+//
+// ProcessInfo::newInstance() is way at the bottom so it can see all of the
+// implementations of the UnixProcessInfo abstract class.
+//
+
+NullProcessInfo::NullProcessInfo(int pid,bool enableEnvironmentRead)
+    : ProcessInfo(pid,enableEnvironmentRead)
+{
+}
+
+bool NullProcessInfo::readProcessInfo(int /*pid*/ , bool /*enableEnvironmentRead*/)
+{
+    return false;
+}
+
+void NullProcessInfo::readUserName()
+{
+}
+
+UnixProcessInfo::UnixProcessInfo(int pid,bool enableEnvironmentRead)
+    : ProcessInfo(pid,enableEnvironmentRead)
+{
+}
+
+bool UnixProcessInfo::readProcessInfo(int pid , bool enableEnvironmentRead)
+{
+    bool ok = readProcInfo(pid);
+    if (ok)
+    {
+        ok |= readArguments(pid);
+        ok |= readCurrentDir(pid);
+        if ( enableEnvironmentRead )
+        {
+            ok |= readEnvironment(pid);
+        }
+    }
+    return ok;
+}
+
+void UnixProcessInfo::readUserName()
+{
+    bool ok = false;
+    int uid = userId(&ok);
+    if (!ok) return;
+
+    struct passwd passwdStruct;
+    struct passwd *getpwResult;
+    char *getpwBuffer;
+    long getpwBufferSize;
+    int getpwStatus;
+
+    getpwBufferSize = sysconf(_SC_GETPW_R_SIZE_MAX);
+    if (getpwBufferSize == -1)
+        getpwBufferSize = 16384;
+
+    getpwBuffer = new char[getpwBufferSize];
+    if (getpwBuffer == NULL)
+        return;
+    getpwStatus = getpwuid_r(uid, &passwdStruct, getpwBuffer, getpwBufferSize, &getpwResult);
+    if (getpwResult != NULL)
+        setUserName(QString(passwdStruct.pw_name));
+    else
+        setUserName(QString());
+    delete [] getpwBuffer;
+}
+
+
+class LinuxProcessInfo : public UnixProcessInfo
+{
+public:
+    LinuxProcessInfo(int pid, bool env) :
+        UnixProcessInfo(pid,env)
+    {
+    }
+
+private:
+    virtual bool readProcInfo(int pid)
+    {
+        // indicies of various fields within the process status file which
+        // contain various information about the process
+        const int PARENT_PID_FIELD = 3;
+        const int PROCESS_NAME_FIELD = 1;
+        const int GROUP_PROCESS_FIELD = 7;
+
+        QString parentPidString;
+        QString processNameString;
+        QString foregroundPidString;
+        QString uidLine;
+        QString uidString;
+        QStringList uidStrings;
+
+        // For user id read process status file ( /proc/<pid>/status )
+        //  Can not use getuid() due to it does not work for 'su'
+        QFile statusInfo( QString("/proc/%1/status").arg(pid) );
+        if ( statusInfo.open(QIODevice::ReadOnly) )
+        {
+            QTextStream stream(&statusInfo);
+            QString statusLine;
+            do {
+                statusLine = stream.readLine(0);
+                if (statusLine.startsWith(QLatin1String("Uid:")))
+                    uidLine = statusLine;
+            } while (!statusLine.isNull() && uidLine.isNull());
+
+            uidStrings << uidLine.split('\t', QString::SkipEmptyParts);
+            // Must be 5 entries: 'Uid: %d %d %d %d' and
+            // uid string must be less than 5 chars (uint)
+            if (uidStrings.size() == 5)
+                uidString = uidStrings[1];
+            if (uidString.size() > 5)
+                uidString.clear();
+
+            bool ok = false;
+            int uid = uidString.toInt(&ok);
+            if (ok)
+                setUserId(uid);
+            readUserName();
+        }
+        else
+        {
+            setFileError( statusInfo.error() );
+            return false;
+        }
+
+
+        // read process status file ( /proc/<pid/stat )
+        //
+        // the expected file format is a list of fields separated by spaces, using
+        // parenthesies to escape fields such as the process name which may itself contain
+        // spaces:
+        //
+        // FIELD FIELD (FIELD WITH SPACES) FIELD FIELD
+        //
+        QFile processInfo( QString("/proc/%1/stat").arg(pid) );
+        if ( processInfo.open(QIODevice::ReadOnly) )
+        {
+            QTextStream stream(&processInfo);
+            QString data = stream.readAll();
+
+            int stack = 0;
+            int field = 0;
+            int pos = 0;
+
+            while (pos < data.count())
+            {
+                QChar c = data[pos];
+
+                if ( c == '(' )
+                    stack++;
+                else if ( c == ')' )
+                    stack--;
+                else if ( stack == 0 && c == ' ' )
+                    field++;
+                else
+                {
+                    switch ( field )
+                    {
+                        case PARENT_PID_FIELD:
+                            parentPidString.append(c);
+                            break;
+                        case PROCESS_NAME_FIELD:
+                            processNameString.append(c);
+                            break;
+                        case GROUP_PROCESS_FIELD:
+                            foregroundPidString.append(c);
+                            break;
+                    }
+                }
+
+                pos++;
+            }
+        }
+        else
+        {
+            setFileError( processInfo.error() );
+            return false;
+        }
+
+        // check that data was read successfully
+        bool ok = false;
+        int foregroundPid = foregroundPidString.toInt(&ok);
+        if (ok)
+            setForegroundPid(foregroundPid);
+
+        int parentPid = parentPidString.toInt(&ok);
+        if (ok)
+            setParentPid(parentPid);
+
+        if (!processNameString.isEmpty())
+            setName(processNameString);
+
+        // update object state
+        setPid(pid);
+
+        return ok;
+    }
+
+    virtual bool readArguments(int pid)
+    {
+        // read command-line arguments file found at /proc/<pid>/cmdline
+        // the expected format is a list of strings delimited by null characters,
+        // and ending in a double null character pair.
+
+        QFile argumentsFile( QString("/proc/%1/cmdline").arg(pid) );
+        if ( argumentsFile.open(QIODevice::ReadOnly) )
+        {
+            QTextStream stream(&argumentsFile);
+            QString data = stream.readAll();
+
+            QStringList argList = data.split( QChar('\0') );
+
+            foreach ( const QString &entry , argList )
+            {
+                if (!entry.isEmpty())
+                    addArgument(entry);
+            }
+        }
+        else
+        {
+            setFileError( argumentsFile.error() );
+        }
+
+        return true;
+    }
+
+    virtual bool readCurrentDir(int pid)
+    {
+        QFileInfo info( QString("/proc/%1/cwd").arg(pid) );
+
+        const bool readable = info.isReadable();
+
+        if ( readable && info.isSymLink() )
+        {
+            setCurrentDir( info.symLinkTarget() );
+            return true;
+        }
+        else
+        {
+            if ( !readable )
+                setError( PermissionsError );
+            else
+                setError( UnknownError );
+
+            return false;
+        }
+    }
+
+    virtual bool readEnvironment(int pid)
+    {
+        // read environment bindings file found at /proc/<pid>/environ
+        // the expected format is a list of KEY=VALUE strings delimited by null
+        // characters and ending in a double null character pair.
+
+        QFile environmentFile( QString("/proc/%1/environ").arg(pid) );
+        if ( environmentFile.open(QIODevice::ReadOnly) )
+        {
+            QTextStream stream(&environmentFile);
+            QString data = stream.readAll();
+
+            QStringList bindingList = data.split( QChar('\0') );
+
+            foreach( const QString &entry , bindingList )
+            {
+                QString name;
+                QString value;
+
+                int splitPos = entry.indexOf('=');
+
+                if ( splitPos != -1 )
+                {
+                    name = entry.mid(0,splitPos);
+                    value = entry.mid(splitPos+1,-1);
+
+                    addEnvironmentBinding(name,value);
+                }
+            }
+        }
+        else
+        {
+            setFileError( environmentFile.error() );
+        }
+
+        return true;
+    }
+} ;
+
+#if defined(Q_OS_FREEBSD)
+class FreeBSDProcessInfo : public UnixProcessInfo
+{
+public:
+    FreeBSDProcessInfo(int pid, bool readEnvironment) :
+        UnixProcessInfo(pid, readEnvironment)
+    {
+    }
+
+private:
+    virtual bool readProcInfo(int pid)
+    {
+        int managementInfoBase[4];
+        size_t mibLength;
+        struct kinfo_proc* kInfoProc;
+
+        managementInfoBase[0] = CTL_KERN;
+        managementInfoBase[1] = KERN_PROC;
+        managementInfoBase[2] = KERN_PROC_PID;
+        managementInfoBase[3] = pid;
+
+        if (sysctl(managementInfoBase, 4, NULL, &mibLength, NULL, 0) == -1)
+            return false;
+
+        kInfoProc = new struct kinfo_proc [mibLength];
+
+        if (sysctl(managementInfoBase, 4, kInfoProc, &mibLength, NULL, 0) == -1)
+        {
+            delete [] kInfoProc;
+            return false;
+        }
+
+#if defined(__DragonFly__)
+        setName(kInfoProc->kp_comm);
+        setPid(kInfoProc->kp_pid);
+        setParentPid(kInfoProc->kp_ppid);
+        setForegroundPid(kInfoProc->kp_pgid);
+        setUserId(kInfoProc->kp_uid);
+#else
+        setName(kInfoProc->ki_comm);
+        setPid(kInfoProc->ki_pid);
+        setParentPid(kInfoProc->ki_ppid);
+        setForegroundPid(kInfoProc->ki_pgid);
+        setUserId(kInfoProc->ki_uid);
+#endif
+
+        readUserName();
+
+        delete [] kInfoProc;
+        return true;
+    }
+
+    virtual bool readArguments(int pid)
+    {
+        char args[ARG_MAX];
+        int managementInfoBase[4];
+        size_t len;
+
+        managementInfoBase[0] = CTL_KERN;
+        managementInfoBase[1] = KERN_PROC;
+        managementInfoBase[2] = KERN_PROC_PID;
+        managementInfoBase[3] = pid;
+
+        len = sizeof(args);
+        if (sysctl(managementInfoBase, 4, args, &len, NULL, 0) == -1)
+            return false;
+
+        const QStringList argumentList = QString(args).split(QChar('\0'));
+
+        for (QStringList::const_iterator it = argumentList.begin(); it != argumentList.end(); ++it)
+        {
+            addArgument(*it);
+        }
+
+        return true;
+    }
+
+    virtual bool readEnvironment(int pid)
+    {
+        // Not supported in FreeBSD?
+        return false;
+    }
+
+    virtual bool readCurrentDir(int pid)
+    {
+#if defined(__DragonFly__)
+        char buf[PATH_MAX];
+        int managementInfoBase[4];
+        size_t len;
+
+        managementInfoBase[0] = CTL_KERN;
+        managementInfoBase[1] = KERN_PROC;
+        managementInfoBase[2] = KERN_PROC_CWD;
+        managementInfoBase[3] = pid;
+
+        len = sizeof(buf);
+        if (sysctl(managementInfoBase, 4, buf, &len, NULL, 0) == -1)
+            return false;
+
+        setCurrentDir(buf);
+
+        return true;
+#else
+        int numrecords;
+        struct kinfo_file* info = 0;
+
+        info = kinfo_getfile(pid, &numrecords);
+
+        if (!info)
+            return false;
+
+        for (int i = 0; i < numrecords; ++i)
+        {
+            if (info[i].kf_fd == KF_FD_TYPE_CWD)
+            {
+                setCurrentDir(info[i].kf_path);
+
+                free(info);
+                return true;
+            }
+        }
+
+        free(info);
+        return false;
+#endif
+    }
+} ;
+#endif
+
+#if defined(Q_OS_MAC)
+class MacProcessInfo : public UnixProcessInfo
+{
+public:
+    MacProcessInfo(int pid, bool env) :
+        UnixProcessInfo(pid, env)
+    {
+    }
+
+private:
+    virtual bool readProcInfo(int pid)
+    {
+        int managementInfoBase[4];
+        size_t mibLength;
+        struct kinfo_proc* kInfoProc;
+        KDE_struct_stat statInfo;
+
+        // Find the tty device of 'pid' (Example: /dev/ttys001)
+        managementInfoBase[0] = CTL_KERN;
+        managementInfoBase[1] = KERN_PROC;
+        managementInfoBase[2] = KERN_PROC_PID;
+        managementInfoBase[3] = pid;
+
+        if (sysctl(managementInfoBase, 4, NULL, &mibLength, NULL, 0) == -1)
+        {
+            return false;
+        } 
+        else
+        {
+            kInfoProc = new struct kinfo_proc [mibLength];
+            if (sysctl(managementInfoBase, 4, kInfoProc, &mibLength, NULL, 0) == -1)
+            {
+                delete [] kInfoProc;
+                return false;
+            }
+            else
+            { 
+                QString deviceNumber = QString(devname(((&kInfoProc->kp_eproc)->e_tdev), S_IFCHR));
+                QString fullDeviceName =  QString("/dev/") + deviceNumber.rightJustified(3, '0');
+                delete [] kInfoProc;
+
+                QByteArray deviceName = fullDeviceName.toLatin1();
+                const char* ttyName = deviceName.data();
+
+                if (KDE_stat(ttyName, &statInfo) != 0)
+                    return false;
+
+                // Find all processes attached to ttyName
+                managementInfoBase[0] = CTL_KERN;
+                managementInfoBase[1] = KERN_PROC;
+                managementInfoBase[2] = KERN_PROC_TTY;
+                managementInfoBase[3] = statInfo.st_rdev;
+
+                mibLength = 0;
+                if (sysctl(managementInfoBase, sizeof(managementInfoBase)/sizeof(int), NULL, &mibLength, NULL, 0) == -1)
+                    return false;
+
+                kInfoProc = new struct kinfo_proc [mibLength];
+                if (sysctl(managementInfoBase, sizeof(managementInfoBase)/sizeof(int), kInfoProc, &mibLength, NULL, 0) == -1)
+                    return false;
+
+                // The foreground program is the first one
+                setName(QString(kInfoProc->kp_proc.p_comm));
+
+                delete [] kInfoProc;
+            }
+        }
+        return true;
+    }
+
+    virtual bool readArguments(int pid)
+    {
+        Q_UNUSED(pid);
+        return false;
+    }
+    virtual bool readCurrentDir(int pid)
+    {
+        struct proc_vnodepathinfo vpi;
+        int nb = proc_pidinfo(pid, PROC_PIDVNODEPATHINFO, 0, &vpi, sizeof(vpi));
+        if (nb == sizeof(vpi))
+        {
+            setCurrentDir(QString(vpi.pvi_cdir.vip_path));
+            return true;
+        }
+        return false;
+    }
+    virtual bool readEnvironment(int pid)
+    {
+        Q_UNUSED(pid);
+        return false;
+    }
+} ;
+#endif
+
+#ifdef Q_OS_SOLARIS
+    // The procfs structure definition requires off_t to be
+    // 32 bits, which only applies if FILE_OFFSET_BITS=32.
+    // Futz around here to get it to compile regardless,
+    // although some of the structure sizes might be wrong.
+    // Fortunately, the structures we actually use don't use
+    // off_t, and we're safe.
+    #if defined(_FILE_OFFSET_BITS) && (_FILE_OFFSET_BITS==64)
+        #undef _FILE_OFFSET_BITS
+    #endif
+    #include <procfs.h>
+#else
+    // On non-Solaris platforms, define a fake psinfo structure
+    // so that the SolarisProcessInfo class can be compiled
+    //
+    // That avoids the trap where you change the API and
+    // don't notice it in #ifdeffed platform-specific parts
+    // of the code.
+    struct psinfo {
+        int pr_ppid;
+        int pr_pgid;
+        char* pr_fname;
+        char* pr_psargs;
+    } ;
+    static const int PRARGSZ=1;
+#endif
+
+class SolarisProcessInfo : public UnixProcessInfo
+{
+public:
+    SolarisProcessInfo(int pid, bool readEnvironment) 
+    : UnixProcessInfo(pid,readEnvironment)
+    {
+    }
+private:
+    virtual bool readProcInfo(int pid)
+    {
+        QFile psinfo( QString("/proc/%1/psinfo").arg(pid) );
+        if ( psinfo.open( QIODevice::ReadOnly ) )
+        {
+            struct psinfo info;
+            if (psinfo.read((char *)&info,sizeof(info)) != sizeof(info))
+            {
+                return false;
+            }
+
+            setParentPid(info.pr_ppid);
+            setForegroundPid(info.pr_pgid);
+            setName(info.pr_fname);
+            setPid(pid);
+
+            // Bogus, because we're treating the arguments as one single string
+            info.pr_psargs[PRARGSZ-1]=0;
+            addArgument(info.pr_psargs);
+        }
+        return true;
+    }
+
+    virtual bool readArguments(int /*pid*/)
+    {
+        // Handled in readProcInfo()
+        return false;
+    }
+
+    virtual bool readEnvironment(int /*pid*/)
+    {
+        // Not supported in Solaris
+        return false;
+    }
+
+    virtual bool readCurrentDir(int pid)
+    {
+        QFileInfo info( QString("/proc/%1/path/cwd").arg(pid) );
+        const bool readable = info.isReadable();
+
+        if ( readable && info.isSymLink() )
+        {
+            setCurrentDir( info.symLinkTarget() );
+            return true;
+        }
+        else
+        {
+            if ( !readable )
+                setError( PermissionsError );
+            else
+                setError( UnknownError );
+
+            return false;
+        }
+    }
+} ;
+
+SSHProcessInfo::SSHProcessInfo(const ProcessInfo& process)
+ : _process(process)
+{
+    bool ok = false;
+
+    // check that this is a SSH process
+    const QString& name = _process.name(&ok);
+
+    if ( !ok || name != "ssh" )
+    {
+        //if ( !ok )
+        //    kWarning() << "Could not read process info";
+        //else
+        //    kWarning() << "Process is not a SSH process";
+
+        return;
+    }
+
+    // read arguments
+    const QVector<QString>& args = _process.arguments(&ok); 
+
+    // SSH options
+    // these are taken from the SSH manual ( accessed via 'man ssh' )
+    
+    // options which take no arguments
+    static const QString noOptionsArguments("1246AaCfgkMNnqsTtVvXxY"); 
+    // options which take one argument
+    static const QString singleOptionArguments("bcDeFiLlmOopRSw");
+
+    if ( ok )
+    {
+         // find the username, host and command arguments
+         //
+         // the username/host is assumed to be the first argument 
+         // which is not an option
+         // ( ie. does not start with a dash '-' character )
+         // or an argument to a previous option.
+         //
+         // the command, if specified, is assumed to be the argument following
+         // the username and host
+         //
+         // note that we skip the argument at index 0 because that is the
+         // program name ( expected to be 'ssh' in this case )
+         for ( int i = 1 ; i < args.count() ; i++ )
+         {
+            // if this argument is an option then skip it, plus any 
+            // following arguments which refer to this option
+            if ( args[i].startsWith('-') )
+            {
+                QChar argChar = ( args[i].length() > 1 ) ? args[i][1] : '\0';
+
+                if ( noOptionsArguments.contains(argChar) )
+                    continue;
+                else if ( singleOptionArguments.contains(argChar) )
+                {
+                    i++;
+                    continue;
+                }
+            }
+
+            // check whether the host has been found yet
+            // if not, this must be the username/host argument 
+            if ( _host.isEmpty() )
+            {
+                // check to see if only a hostname is specified, or whether
+                // both a username and host are specified ( in which case they
+                // are separated by an '@' character:  username@host )
+            
+                int separatorPosition = args[i].indexOf('@');
+                if ( separatorPosition != -1 )
+                {
+                    // username and host specified
+                    _user = args[i].left(separatorPosition);
+                    _host = args[i].mid(separatorPosition+1);
+                }
+                else
+                {
+                    // just the host specified
+                    _host = args[i];
+                }
+            }
+            else
+            {
+                // host has already been found, this must be the command argument
+                _command = args[i];
+            }
+
+         }
+    }
+    else
+    {
+        //kWarning() << "Could not read arguments";
+        
+        return;
+    }
+}
+
+QString SSHProcessInfo::userName() const
+{
+    return _user;
+}
+QString SSHProcessInfo::host() const
+{
+    return _host;
+}
+QString SSHProcessInfo::command() const
+{
+    return _command;
+}
+QString SSHProcessInfo::format(const QString& input) const
+{
+    QString output(input);
+   
+    // test whether host is an ip address
+    // in which case 'short host' and 'full host'
+    // markers in the input string are replaced with
+    // the full address
+    bool isIpAddress = false;
+   
+    struct in_addr address;
+    if ( inet_aton(_host.toLocal8Bit().constData(),&address) != 0 )
+        isIpAddress = true;
+    else
+        isIpAddress = false;
+
+    // search for and replace known markers
+    output.replace("%u",_user);
+
+    if ( isIpAddress )
+        output.replace("%h",_host);
+    else
+        output.replace("%h",_host.left(_host.indexOf('.')));
+    
+    output.replace("%H",_host);
+    output.replace("%c",_command);
+
+    return output;
+}
+
+ProcessInfo* ProcessInfo::newInstance(int pid,bool enableEnvironmentRead)
+{
+#ifdef Q_OS_LINUX
+    return new LinuxProcessInfo(pid,enableEnvironmentRead);
+#elif defined(Q_OS_SOLARIS)
+    return new SolarisProcessInfo(pid,enableEnvironmentRead);
+#elif defined(Q_OS_MAC)
+    return new MacProcessInfo(pid,enableEnvironmentRead);
+#elif defined(Q_OS_FREEBSD)
+    return new FreeBSDProcessInfo(pid,enableEnvironmentRead);
+#else
+    return new NullProcessInfo(pid,enableEnvironmentRead);
+#endif
+}
+
new file mode 100644
--- /dev/null
+++ b/gui//src/ProcessInfo.h
@@ -0,0 +1,454 @@
+/*
+    Copyright 2007-2008 by Robert Knight <robertknight@gmail.com>
+
+    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 PROCESSINFO_H
+#define PROCESSINFO_H
+
+// Qt
+#include <QtCore/QFile>
+#include <QtCore/QMap>
+#include <QtCore/QString>
+#include <QtCore/QVector>
+
+/**
+ * Takes a snapshot of the state of a process and provides access to 
+ * information such as the process name, parent process,
+ * the foreground process in the controlling terminal,
+ * the arguments with which the process was started and the 
+ * environment.
+ *
+ * To create a new snapshot, construct a new ProcessInfo instance,
+ * using ProcessInfo::newInstance(),
+ * passing the process identifier of the process you are interested in.
+ *
+ * After creating a new instance, call the update() method to take a 
+ * snapshot of the current state of the process.
+ *
+ * Before calling any additional methods, check that the process state
+ * was read successfully using the isValid() method.
+ *
+ * Each accessor method which provides information about the process state ( such as pid(), 
+ * currentDir(), name() ) takes a pointer to a boolean as an argument.  If the information
+ * requested was read successfully then the boolean is set to true, otherwise it is set
+ * to false, in which case the return value from the function should be ignored.
+ * If this boolean is set to false, it may indicate an error reading the process information,
+ * or it may indicate that the information is not available on the current platform. 
+ *
+ * eg.
+ *
+ * @code
+ *   ProcessInfo* info = ProcessInfo::newInstance(pid);
+ *   info->update();
+ *
+ *   if ( info->isValid() )
+ *   {
+ *      bool ok;
+ *      QString value = info->name(&ok);
+ *
+ *      if ( ok ) kDebug() << "process name - " << name;
+ *      int parentPid = info->parentPid(&ok);
+ *      if ( ok ) kDebug() << "parent process - " << parentPid;
+ *      int foregroundPid = info->foregroundColororegroundPid(&ok);
+ *      if ( ok ) kDebug() << "foreground process - " << foregroundPid;
+ *   }
+ * @endcode
+ */
+class ProcessInfo
+{
+public:
+    /**
+     * Constructs a new instance of a suitable ProcessInfo sub-class for 
+     * the current platform which provides information about a given process.
+     *
+     * @param pid The pid of the process to examine
+     * @param readEnvironment Specifies whether environment bindings should
+     * be read.  If this is false, then environment() calls will
+     * always fail.  This is an optimization to avoid the overhead
+     * of reading the (potentially large) environment data when it
+     * is not required. 
+     */
+    static ProcessInfo* newInstance(int pid,bool readEnvironment = false);
+
+    virtual ~ProcessInfo() {}
+
+    /** 
+     * Updates the information about the process.  This must
+     * be called before attempting to use any of the accessor methods.
+     */
+    void update();
+
+    /** Returns true if the process state was read successfully. */ 
+    bool isValid() const;
+    /** 
+     * Returns the process id.  
+     *
+     * @param ok Set to true if the process id was read successfully or false otherwise 
+     */
+    int pid(bool* ok) const;
+    /** 
+     * Returns the id of the parent process id was read successfully or false otherwise
+     * 
+     * @param ok Set to true if the parent process id
+     */
+    int parentPid(bool* ok) const;
+    
+    /** 
+     * Returns the id of the current foreground process 
+     *
+     * NOTE:  Using the foregroundProcessGroup() method of the Pty
+     * instance associated with the terminal of interest is preferred
+     * over using this method.
+     *
+     * @param ok Set to true if the foreground process id was read successfully or false otherwise
+     */
+    int foregroundPid(bool* ok) const;
+    
+    /* Returns the user id of the process */
+    int userId(bool* ok) const;
+
+    /** Returns the user's name of the process */
+    QString userName() const;
+   
+    /** Returns the user's home directory of the process */
+    QString userHomeDir() const;
+
+    /** Returns the name of the current process */
+    QString name(bool* ok) const;
+   
+    /** 
+     * Returns the command-line arguments which the process
+     * was started with.
+     *
+     * The first argument is the name used to launch the process.
+     *
+     * @param ok Set to true if the arguments were read successfully or false otherwise.
+     */
+    QVector<QString> arguments(bool* ok) const;
+    /**
+     * Returns the environment bindings which the process
+     * was started with.
+     * In the returned map, the key is the name of the environment variable,
+     * and the value is the corresponding value.
+     *
+     * @param ok Set to true if the environment bindings were read successfully or false otherwise
+     */
+    QMap<QString,QString> environment(bool* ok) const;
+
+    /**
+     * Returns the current working directory of the process
+     *
+     * @param ok Set to true if the current working directory was read successfully or false otherwise
+     */
+    QString currentDir(bool* ok) const;
+
+    /**
+     * Returns the current working directory of the process (or its parent)
+     */
+    QString validCurrentDir() const;
+
+    /** Forces the user home directory to be calculated */
+    void setUserHomeDir();
+
+    /**
+     * Parses an input string, looking for markers beginning with a '%' 
+     * character and returns a string with the markers replaced
+     * with information from this process description.
+     * <br>
+     * The markers recognised are:
+     * <ul>
+     * <li> %u - Name of the user which owns the process. </li>
+     * <li> %n - Replaced with the name of the process.   </li>
+     * <li> %d - Replaced with the last part of the path name of the 
+     *      process' current working directory.
+     *      
+     *      (eg. if the current directory is '/home/bob' then
+     *      'bob' would be returned)
+     * </li>
+     * <li> %D - Replaced with the current working directory of the process. </li>
+     * </ul>
+     */
+    QString format(const QString& text) const;
+
+    /** 
+     * This enum describes the errors which can occur when trying to read 
+     * a process's information.
+     */
+    enum Error
+    {
+        /** No error occurred. */
+        NoError,
+        /** The nature of the error is unknown. */
+        UnknownError,
+        /** Konsole does not have permission to obtain the process information. */
+        PermissionsError
+    };
+
+    /**
+     * Returns the last error which occurred.
+     */
+    Error error() const;
+
+protected:
+    /**
+     * Constructs a new process instance.  You should not call the constructor
+     * of ProcessInfo or its subclasses directly.  Instead use the 
+     * static ProcessInfo::newInstance() method which will return
+     * a suitable ProcessInfo instance for the current platform.
+     */ 
+    explicit ProcessInfo(int pid , bool readEnvironment = false);
+
+    /** 
+     * This is called on construction to read the process state 
+     * Subclasses should reimplement this function to provide
+     * platform-specific process state reading functionality.
+     *
+     * When called, readProcessInfo() should attempt to read all
+     * of the necessary state information.  If the attempt is successful,
+     * it should set the process id using setPid(), and update
+     * the other relevant information using setParentPid(), setName(),
+     * setArguments() etc.
+     *
+     * Calls to isValid() will return true only if the process id
+     * has been set using setPid()
+     *
+     * @param pid The process id of the process to read
+     * @param readEnvironment Specifies whether the environment bindings
+     *                        for the process should be read
+     */
+    virtual bool readProcessInfo(int pid , bool readEnvironment) = 0;
+
+    /* Read the user name */
+    virtual void readUserName(void) = 0;
+
+    /** Sets the process id associated with this ProcessInfo instance */
+    void setPid(int pid);
+    /** Sets the parent process id as returned by parentPid() */
+    void setParentPid(int pid);
+    /** Sets the foreground process id as returend by foregroundPid() */
+    void setForegroundPid(int pid);
+    /** Sets the user id associated with this ProcessInfo instance */
+    void setUserId(int uid);
+    /** Sets the user name of the process as set by readUserName() */
+    void setUserName(const QString& name);
+    /** Sets the name of the process as returned by name() */
+    void setName(const QString& name);
+    /** Sets the current working directory for the process */
+    void setCurrentDir(const QString& dir);
+
+    /** Sets the error */
+    void setError( Error error );
+
+    /** Convenience method.  Sets the error based on a QFile error code. */ 
+    void setFileError( QFile::FileError error ); 
+
+    /** 
+     * Adds a commandline argument for the process, as returned
+     * by arguments()
+     */
+    void addArgument(const QString& argument);
+    /**
+     * Adds an environment binding for the process, as returned by
+     * environment()
+     *
+     * @param name The name of the environment variable, eg. "PATH"
+     * @param value The value of the environment variable, eg. "/bin"
+     */
+    void addEnvironmentBinding(const QString& name , const QString& value);
+
+private:
+    enum CommandFormat
+    {
+        ShortCommandFormat,
+        LongCommandFormat
+    };
+    // takes a process name and its arguments and produces formatted output
+    QString formatCommand(const QString& name , const QVector<QString>& arguments , 
+                          CommandFormat format) const;
+
+    // valid bits for _fields variable, ensure that
+    // _fields is changed to an int if more than 8 fields are added
+    enum FIELD_BITS
+    {
+        PROCESS_ID          = 1,
+        PARENT_PID          = 2,
+        FOREGROUND_PID      = 4,
+        ARGUMENTS           = 8,
+        ENVIRONMENT         = 16,
+        NAME                = 32,
+        CURRENT_DIR         = 64,
+        UID                 =128 
+    };
+
+    char _fields; // a bitmap indicating which fields are valid
+                  // used to set the "ok" parameters for the public
+                  // accessor functions
+
+    bool _enableEnvironmentRead; // specifies whether to read the environment
+                                 // bindings when update() is called
+    int _pid;  
+    int _parentPid;
+    int _foregroundPid;
+    int _userId;  
+
+    Error _lastError;
+
+    QString _name;
+    QString _userName;
+    QString _userHomeDir;
+    QString _currentDir;
+
+    QVector<QString> _arguments;
+    QMap<QString,QString> _environment;
+};
+
+/** 
+ * Implementation of ProcessInfo which does nothing.
+ * Used on platforms where a suitable ProcessInfo subclass is not 
+ * available.
+ *
+ * isValid() will always return false for instances of NullProcessInfo
+ */
+class NullProcessInfo : public ProcessInfo
+{
+public:
+    /** 
+     * Constructs a new NullProcessInfo instance.
+     * See ProcessInfo::newInstance()
+     */
+    explicit NullProcessInfo(int pid,bool readEnvironment = false);
+protected:
+    virtual bool readProcessInfo(int pid,bool readEnvironment);
+    virtual void readUserName(void);
+};
+
+/**
+ * Implementation of ProcessInfo for Unix platforms which uses
+ * the /proc filesystem
+ */
+class UnixProcessInfo : public ProcessInfo
+{
+public:
+    /** 
+     * Constructs a new instance of UnixProcessInfo.
+     * See ProcessInfo::newInstance()
+     */
+    explicit UnixProcessInfo(int pid,bool readEnvironment = false);
+
+protected:
+    /** 
+     * Implementation of ProcessInfo::readProcessInfo(); calls the
+     * four private methods below in turn.
+     */
+    virtual bool readProcessInfo(int pid , bool readEnvironment);
+
+    virtual void readUserName(void);
+
+private:
+    /**
+     * Read the standard process information -- PID, parent PID, foreground PID.
+     * @param pid process ID to use
+     * @return true on success
+     */
+    virtual bool readProcInfo(int pid)=0;
+
+    /**
+     * Read the environment of the process. Sets _environment.
+     * @param pid process ID to use
+     * @return true on success
+     */
+    virtual bool readEnvironment(int pid)=0;
+
+    /**
+     * Determine what arguments were passed to the process. Sets _arguments.
+     * @param pid process ID to use
+     * @return true on success
+     */
+    virtual bool readArguments(int pid)=0;
+
+    /**
+     * Determine the current directory of the process.
+     * @param pid process ID to use
+     * @return true on success
+     */
+    virtual bool readCurrentDir(int pid)=0;
+};
+
+/** 
+ * Lightweight class which provides additional information about SSH processes.
+ */
+class SSHProcessInfo
+{
+public:
+    /** 
+     * Constructs a new SSHProcessInfo instance which provides additional
+     * information about the specified SSH process.
+     *
+     * @param process A ProcessInfo instance for a SSH process.
+     */
+    SSHProcessInfo(const ProcessInfo& process);
+
+    /** 
+     * Returns the user name which the user initially logged into on
+     * the remote computer.
+     */
+    QString userName() const;
+
+    /**
+     * Returns the host which the user has connected to.
+     */
+    QString host() const;
+
+    /** 
+     * Returns the command which the user specified to execute on the 
+     * remote computer when starting the SSH process.
+     */
+    QString command() const;
+
+    /**
+     * Operates in the same way as ProcessInfo::format(), except
+     * that the set of markers understood is different:
+     *
+     * %u - Replaced with user name which the user initially logged
+     *      into on the remote computer.
+     * %h - Replaced with the first part of the host name which
+     *      is connected to.
+     * %H - Replaced with the full host name of the computer which
+     *      is connected to.
+     * %c - Replaced with the command which the user specified
+     *      to execute when starting the SSH process.
+     */
+    QString format(const QString& input) const;
+
+private:
+    const ProcessInfo& _process;
+    QString _user;
+    QString _host;
+    QString _command;
+};
+
+#endif //PROCESSINFO_H
+
+/*
+  Local Variables:
+  mode: c++
+  c-file-style: "stroustrup"
+  indent-tabs-mode: nil
+  tab-width: 4
+  End:
+*/
new file mode 100644
--- /dev/null
+++ b/gui//src/Pty.cpp
@@ -0,0 +1,310 @@
+/*
+    This file is part of Konsole, an X terminal.
+    Copyright 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
+
+    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 "kprocess_p.h"
+#include "kptyprocess.h"
+#include "Pty.h"
+
+// System
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+#include <termios.h>
+#include <signal.h>
+
+// Qt
+#include <QtCore/QStringList>
+
+#include "kpty.h"
+#include "kptydevice.h"
+
+
+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::setFlowControlEnabled(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))
+    //  kWarning() << "Unable to set terminal attributes.";
+  }
+}
+bool Pty::flowControlEnabled() const
+{
+    if (pty()->masterFd() >= 0)
+    {
+        struct ::termios ttmode;
+        pty()->tcGetAttr(&ttmode);
+        return ttmode.c_iflag & IXOFF &&
+               ttmode.c_iflag & IXON;
+    }  
+    //kWarning() << "Unable to get flow control status, terminal not connected.";
+    return false;
+}
+
+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))
+    //  kWarning() << "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))
+    //  kWarning() << "Unable to set terminal attributes.";
+  }
+}
+
+char Pty::erase() const
+{
+    if (pty()->masterFd() >= 0)
+    {
+        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);
+
+            setEnv(variable,value);
+        }
+    }
+}
+
+int Pty::start(const QString& program, 
+               const QStringList& programArguments, 
+               const QStringList& environment, 
+               ulong winid, 
+               bool addToUtmp,
+               const QString& dbusService, 
+               const QString& dbusSession)
+{
+  clearProgram();
+
+  // For historical reasons, the first argument in programArguments is the 
+  // name of the program to execute, so create a list consisting of all
+  // but the first argument to pass to setProgram()
+  Q_ASSERT(programArguments.count() >= 1);
+  setProgram(program.toLatin1(),programArguments.mid(1));
+
+  addEnvironmentVariables(environment);
+
+  if ( !dbusService.isEmpty() )
+     setEnv("KONSOLE_DBUS_SERVICE",dbusService);
+  if ( !dbusSession.isEmpty() )
+     setEnv("KONSOLE_DBUS_SESSION", dbusSession);
+
+  setEnv("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 messages in the wrong language
+  //
+  // this can happen if LANG contains a language which KDE
+  // does not have a translation for
+  //
+  // BR:149300
+  setEnv("LANGUAGE",QString(),false /* do not overwrite existing value if any */);
+
+  setUseUtmp(addToUtmp);
+
+  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))
+  //  kWarning() << "Unable to set terminal attributes.";
+  
+  pty()->setWinSize(_windowLines, _windowColumns);
+
+  KProcess::start();
+
+  if (!waitForStarted())
+      return -1;
+
+  return 0;
+}
+
+void Pty::setWriteable(bool writeable)
+{
+  //KDE_struct_stat sbuf;
+  struct stat sbuf;
+  //KDE_stat(pty()->ttyName(), &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(int masterFd, QObject* parent)
+    : KPtyProcess(masterFd,parent)
+{
+    init();
+}
+Pty::Pty(QObject* parent)
+    : KPtyProcess(parent)
+{
+    init();
+}
+void Pty::init()
+{
+  _windowColumns = 0;
+  _windowLines = 0;
+  _eraseChar = 0;
+  _xonXoff = true;
+  _utf8 =true;
+
+  connect(pty(), SIGNAL(readyRead()) , this , SLOT(dataReceived()));
+  setPtyChannels(KPtyProcess::AllChannels);
+}
+
+Pty::~Pty()
+{
+}
+
+void Pty::sendData(const char* data, int length)
+{
+  if (!length)
+      return;
+  
+  if (!pty()->write(data,length)) 
+  {
+    //kWarning() << "Pty::doSendJobs - Could not send input data to terminal process.";
+    return;
+  }
+}
+
+void Pty::dataReceived() 
+{
+     QByteArray data = pty()->readAll();
+    emit receivedData(data.constData(),data.count());
+}
+
+void Pty::lockPty(bool lock)
+{
+    Q_UNUSED(lock);
+
+// TODO: Support for locking the Pty
+  //if (lock)
+    //suspend();
+  //else
+    //resume();
+}
+
+int Pty::foregroundProcessGroup() const
+{
+    int pid = tcgetpgrp(pty()->masterFd());
+
+    if ( pid != -1 )
+    {
+        return pid;
+    } 
+
+    return 0;
+}
+
+void Pty::setupChildProcess()
+{
+    KPtyProcess::setupChildProcess();
+    
+    // reset all signal handlers
+    // this ensures that terminal applications respond to 
+    // signals generated via key sequences such as Ctrl+C
+    // (which sends SIGINT)
+    struct sigaction action;
+    sigemptyset(&action.sa_mask);
+    action.sa_handler = SIG_DFL;
+    action.sa_flags = 0;
+    for (int signal=1;signal < NSIG; signal++)
+        sigaction(signal,&action,0L);
+}
new file mode 100644
--- /dev/null
+++ b/gui//src/Pty.h
@@ -0,0 +1,201 @@
+/*
+    This file is part of Konsole, KDE's terminal emulator. 
+    
+    Copyright 2007-2008 by Robert Knight <robertknight@gmail.com>
+    Copyright 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
+
+    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/QSize>
+
+// KDE
+#include "kprocess.h"
+#include "kptyprocess.h"
+
+/**
+ * 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 KONSOLEPRIVATE_EXPORT Pty: public KPtyProcess
+class Pty: public KPtyProcess
+{
+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.
+     */
+    explicit Pty(QObject* parent = 0);
+
+    /** 
+     * Construct a process using an open pty master.
+     * See KPtyProcess::KPtyProcess()
+     */
+    explicit Pty(int ptyMasterFd, QObject* parent = 0);
+
+    ~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.  The flow control setting
+     * may be changed later by a terminal application, so flowControlEnabled()
+     * may not equal the value of @p on in the previous call to setFlowControlEnabled()
+     */
+    void setFlowControlEnabled(bool on);
+
+    /** Queries the terminal state and returns true if Xon/Xoff flow control is enabled. */
+    bool flowControlEnabled() const;
+
+    /** 
+     * 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;
+   
+  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 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);
+   
+  protected:
+      void setupChildProcess();
+
+  private slots:
+    // called when data is received from the terminal process 
+    void dataReceived(); 
+    
+  private:
+      void init();
+
+    // takes a list of key=value pairs and adds them
+    // to the environment for the process
+    void addEnvironmentVariables(const QStringList& environment);
+
+    int  _windowColumns; 
+    int  _windowLines;
+    char _eraseChar;
+    bool _xonXoff;
+    bool _utf8;
+};
+
+#endif // PTY_H
new file mode 100644
--- /dev/null
+++ b/gui//src/QTerminalWidget.cpp
@@ -0,0 +1,191 @@
+/*  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 "QTerminalWidget.h"
+#include "Session.h"
+#include "TerminalDisplay.h"
+
+struct TermWidgetImpl
+{
+    TermWidgetImpl(QWidget* parent = 0);
+
+    TerminalDisplay *m_terminalDisplay;
+    Session *m_session;
+    Session* createSession();
+    TerminalDisplay* createTerminalDisplay(Session *session, QWidget* parent);
+};
+
+TermWidgetImpl::TermWidgetImpl(QWidget* parent)
+{
+    QPalette palette = QApplication::palette();
+    m_session = createSession();
+    m_terminalDisplay = createTerminalDisplay(this->m_session, parent);
+    m_terminalDisplay->setBackgroundColor(palette.color(QPalette::Base));
+    m_terminalDisplay->setForegroundColor(palette.color(QPalette::Text));
+}
+
+Session *TermWidgetImpl::createSession()
+{
+    Session *session = new Session();
+    session->setTitle(Session::NameRole, "QTerminalWidget");
+    session->setProgram("/bin/bash");
+    session->setArguments(QStringList());
+    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(parent);
+    display->setBellMode(TerminalDisplay::NotifyBell);
+    display->setTerminalSizeHint(true);
+    display->setTripleClickMode(TerminalDisplay::SelectWholeLine);
+    display->setTerminalSizeStartup(true);
+    display->setRandomSeed(session->sessionId() * 31);
+    return display;
+}
+
+QTerminalWidget::QTerminalWidget(int startnow, QWidget *parent)
+    :QWidget(parent)
+{
+    m_impl = new TermWidgetImpl(this);
+    
+    initialize();
+
+    if(startnow && m_impl->m_session) {
+	m_impl->m_session->run();
+    }
+
+    setFocus(Qt::OtherFocusReason);
+    m_impl->m_terminalDisplay->resize(this->size());
+    setFocusProxy(m_impl->m_terminalDisplay);
+}
+
+void QTerminalWidget::startShellProgram()
+{
+    if(m_impl->m_session->isRunning())
+	return;
+	
+    m_impl->m_session->run();
+}
+
+void QTerminalWidget::initialize()
+{    
+    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()));
+}
+
+QTerminalWidget::~QTerminalWidget()
+{
+    emit destroyed();
+}
+
+void QTerminalWidget::setTerminalFont(QFont &font)
+{
+    if (!m_impl->m_terminalDisplay)
+	return;
+    m_impl->m_terminalDisplay->setVTFont(font);
+}
+
+void QTerminalWidget::setShellProgram(QString progname)
+{
+    if (!m_impl->m_session)
+	return;
+    m_impl->m_session->setProgram(progname);	
+}
+
+void QTerminalWidget::openTeletype(int fd)
+{
+  if ( m_impl->m_session->isRunning() )
+    return;
+
+  m_impl->m_session->openTeletype(fd);
+}
+
+void QTerminalWidget::setArgs(QStringList &args)
+{
+    if (!m_impl->m_session)
+	return;
+    m_impl->m_session->setArguments(args);	
+}
+
+void QTerminalWidget::setTextCodec(QTextCodec *codec)
+{
+    if (!m_impl->m_session)
+	return;
+    m_impl->m_session->setCodec(codec);	
+}
+
+void QTerminalWidget::setSize(int h, int v)
+{
+    if (!m_impl->m_terminalDisplay)
+	return;
+    m_impl->m_terminalDisplay->setSize(h, v);
+}
+
+void QTerminalWidget::setHistorySize(int lines)
+{
+    if (lines < 0)
+        m_impl->m_session->setHistoryType(HistoryTypeFile());
+    else
+	m_impl->m_session->setHistoryType(HistoryTypeBuffer(lines));
+}
+
+void QTerminalWidget::setScrollBarPosition(ScrollBarPosition pos)
+{
+    if (!m_impl->m_terminalDisplay)
+	return;
+    m_impl->m_terminalDisplay->setScrollBarPosition((TerminalDisplay::ScrollBarPosition)pos);
+}
+
+void QTerminalWidget::sendText(const QString &text)
+{
+    m_impl->m_session->sendText(text); 
+}
+
+void QTerminalWidget::installEventFilterOnDisplay(QObject *object) {
+    m_impl->m_terminalDisplay->installEventFilter(object);
+}
+
+void QTerminalWidget::resizeEvent(QResizeEvent*)
+{
+    m_impl->m_terminalDisplay->resize(this->size());
+    m_impl->m_terminalDisplay->update();
+}
+
+void QTerminalWidget::sessionFinished()
+{
+    emit finished();
+}
+
+
new file mode 100644
--- /dev/null
+++ b/gui//src/QTerminalWidget.h
@@ -0,0 +1,93 @@
+/*  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 QTERMINALWIDGET_H
+#define QTERMINALWIDGET_H
+
+#include <QtGui>
+
+struct TermWidgetImpl;
+/**
+  * \class QTerminalWidget
+  * This class forms a widget class that can be inserted into other widgets.
+  */
+class QTerminalWidget : public QWidget
+{
+    Q_OBJECT
+public:
+    /**
+      * \enum ScrollBarPosition
+      * Defines the scrollbar position of the terminal.
+      */
+    enum ScrollBarPosition
+    {
+        NoScrollBar,
+        ScrollBarLeft,
+        ScrollBarRight
+    };
+
+    QTerminalWidget(int startnow = 1, QWidget *parent = 0);
+    ~QTerminalWidget();
+
+    void startShellProgram();
+    void openTeletype(int fd);
+
+    /** 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);
+    
+    /** Resize terminal widget. */
+    void setSize(int h, int v);
+    
+    /** History size for scrolling, values below zero mean infinite. */
+    void setHistorySize(int lines);
+
+    /** Presence of scrollbar. By default, there is no scrollbar present. */
+    void setScrollBarPosition(ScrollBarPosition);
+    
+    /** Send some text to the terminal. */
+    void sendText(const QString &text);
+
+    /** Installs an event filter onto the display. */
+    void installEventFilterOnDisplay(QObject *object);
+            
+signals:
+    /** Emitted, when the current program has finished. */
+    void finished();
+        
+protected: 
+    virtual void resizeEvent(QResizeEvent *);
+    
+protected slots:
+    void sessionFinished();        
+    
+private:
+    /** Performs initial operations on this widget. */
+    void initialize();
+    TermWidgetImpl *m_impl;
+};
+
+#endif // QTERMINALWIDGET_H
new file mode 100644
--- /dev/null
+++ b/gui//src/Quint.cpp
@@ -0,0 +1,41 @@
+/* Quint - A graphical user interface for Octave
+ * Copyright (C) 2011 Jacob Dawid
+ * jacob.dawid@googlemail.com
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <QtGui/QApplication>
+#include <QTranslator>
+#include <QSettings>
+#include "MainWindow.h"
+
+int main(int argc, char *argv[])
+{
+    QApplication application(argc, argv);
+
+    QDesktopServices desktopServices;
+    QSettings settings(
+                desktopServices.storageLocation(QDesktopServices::HomeLocation)
+                + "/.quint/settings.ini", QSettings::IniFormat);
+
+    QTranslator translator;
+    translator.load(QString("../languages/%1.qm").arg(settings.value("application/language").toString()));
+    application.installTranslator(&translator);
+
+    MainWindow w;
+    w.show();
+
+    return application.exec();
+}
new file mode 100644
--- /dev/null
+++ b/gui//src/Screen.cpp
@@ -0,0 +1,1356 @@
+/*
+   This file is part of Konsole, an X terminal.
+
+   Copyright 2007-2008 by Robert Knight <robert.knight@gmail.com>
+   Copyright 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
+
+   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"
+
+//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),
+    history(new HistoryScrollNone()),
+    cuX(0), cuY(0),
+    currentRendition(0),
+    _topMargin(0), _bottomMargin(0),
+    selBegin(0), selTopLeft(0), selBottomRight(0),
+    blockSelectionMode(false),
+    effectiveForeground(CharacterColor()), effectiveBackground(CharacterColor()), effectiveRendition(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 history;
+}
+
+void Screen::cursorUp(int n)
+    //=CUU
+{
+    if (n == 0) n = 1; // Default
+    int stop = cuY < _topMargin ? 0 : _topMargin;
+    cuX = qMin(columns-1,cuX); // nowrap!
+    cuY = qMax(stop,cuY-n);
+}
+
+void Screen::cursorDown(int n)
+    //=CUD
+{
+    if (n == 0) n = 1; // Default
+    int stop = cuY > _bottomMargin ? lines-1 : _bottomMargin;
+    cuX = qMin(columns-1,cuX); // nowrap!
+    cuY = qMin(stop,cuY+n);
+}
+
+void Screen::cursorLeft(int n)
+    //=CUB
+{
+    if (n == 0) n = 1; // Default
+    cuX = qMin(columns-1,cuX); // nowrap!
+    cuX = qMax(0,cuX-n);
+}
+
+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 ) )
+    { //Debug()<<" setRegion("<<top<<","<<bot<<") : bad range.";
+        return;                   // Default error action: ignore
+    }
+    _topMargin = top;
+    _bottomMargin = bot;
+    cuX = 0;
+    cuY = getMode(MODE_Origin) ? top : 0;
+
+}
+
+int Screen::topMargin() const
+{
+    return _topMargin;
+}
+int Screen::bottomMargin() const
+{
+    return _bottomMargin;
+}
+
+void Screen::index()
+    //=IND
+{
+    if (cuY == _bottomMargin)
+        scrollUp(1);
+    else if (cuY < lines-1)
+        cuY += 1;
+}
+
+void Screen::reverseIndex()
+    //=RI
+{
+    if (cuY == _topMargin)
+        scrollDown(_topMargin,1);
+    else if (cuY > 0)
+        cuY -= 1;
+}
+
+void Screen::nextLine()
+    //=NEL
+{
+    toStartOfLine(); 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() - 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);
+}
+
+void Screen::insertLines(int n)
+{
+    if (n == 0) n = 1; // Default
+    scrollDown(cuY,n);
+}
+
+void Screen::setMode(int m)
+{
+    currentModes[m] = true;
+    switch(m)
+    {
+        case MODE_Origin : cuX = 0; cuY = _topMargin; break; //FIXME: home
+    }
+}
+
+void Screen::resetMode(int m)
+{
+    currentModes[m] = false;
+    switch(m)
+    {
+        case MODE_Origin : cuX = 0; cuY = 0; break; //FIXME: home
+    }
+}
+
+void Screen::saveMode(int m)
+{
+    savedModes[m] = currentModes[m];
+}
+
+void Screen::restoreMode(int m)
+{
+    currentModes[m] = savedModes[m];
+}
+
+bool Screen::getMode(int m) const
+{
+    return currentModes[m];
+}
+
+void Screen::saveCursor()
+{
+    savedState.cursorColumn = cuX;
+    savedState.cursorLine  = cuY;
+    savedState.rendition = currentRendition;
+    savedState.foreground = currentForeground;
+    savedState.background = currentBackground;
+}
+
+void Screen::restoreCursor()
+{
+    cuX     = qMin(savedState.cursorColumn,columns-1);
+    cuY     = qMin(savedState.cursorLine,lines-1);
+    currentRendition   = savedState.rendition; 
+    currentForeground   = savedState.foreground;
+    currentBackground   = savedState.background;
+    updateEffectiveRendition();
+}
+
+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
+        _bottomMargin = 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.
+    _topMargin=0;
+    _bottomMargin=lines-1;
+    initTabStops();
+    clearSelection();
+}
+
+void Screen::setDefaultMargins()
+{
+    _topMargin = 0;
+    _bottomMargin = 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
+
+   currentForeground, currentBackground 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::updateEffectiveRendition()
+{
+    effectiveRendition = currentRendition;
+    if (currentRendition & RE_REVERSE)
+    {
+        effectiveForeground = currentBackground;
+        effectiveBackground = currentForeground;
+    }
+    else
+    {
+        effectiveForeground = currentForeground;
+        effectiveBackground = currentBackground;
+    }
+
+    if (currentRendition & RE_BOLD)
+        effectiveForeground.toggleIntensive();
+}
+
+void Screen::copyFromHistory(Character* dest, int startLine, int count) const
+{
+    Q_ASSERT( startLine >= 0 && count > 0 && startLine + count <= history->getLines() );
+
+    for (int line = startLine; line < startLine + count; line++) 
+    {
+        const int length = qMin(columns,history->getLineLen(line));
+        const int destLineOffset  = (line-startLine)*columns;
+
+        history->getCells(line,0,length,dest + destLineOffset);
+
+        for (int column = length; column < columns; column++) 
+            dest[destLineOffset+column] = defaultChar;
+
+        // invert selected text
+        if (selBegin !=-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 (selBegin != -1 && isSelected(column,line + history->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 < history->getLines() + lines );
+
+    const int mergedLines = endLine - startLine + 1;
+
+    Q_ASSERT( size >= mergedLines * columns ); 
+    Q_UNUSED( size );
+
+    const int linesInHistoryBuffer = qBound(0,history->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 - history->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 < history->getLines() + lines );
+
+    const int mergedLines = endLine-startLine+1;
+    const int linesInHistory = qBound(0,history->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 (history->isWrappedLine(line))
+        {
+            result[index] = (LineProperty)(result[index] | LINE_WRAPPED);
+        }
+        index++;
+    }
+
+    // copy properties for lines in screen buffer
+    const int firstScreenLine = startLine + linesInHistory - history->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);
+
+    _topMargin=0;
+    _bottomMargin=lines-1;
+
+    setDefaultRendition();
+    saveCursor();
+
+    if ( clearScreen )
+        clear();
+}
+
+void Screen::clear()
+{
+    clearEntireScreen();
+    home();
+}
+
+void Screen::backspace()
+{
+    cuX = qMin(columns-1,cuX); // nowrap!
+    cuX = qMax(0,cuX-1);
+
+    if (screenLines[cuY].size() < cuX+1)
+        screenLines[cuY].resize(cuX+1);
+
+    if (BS_CLEARS) 
+        screenLines[cuY][cuX].character = ' ';
+}
+
+void Screen::tab(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::backtab(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()
+{
+    tabStops.resize(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);
+}
+
+void Screen::newLine()
+{
+    if (getMode(MODE_NewLine)) 
+        toStartOfLine();
+    index();
+}
+
+void Screen::checkSelection(int from, int to)
+{
+    if (selBegin == -1) 
+        return;
+    int scr_TL = loc(0, history->getLines());
+    //Clear entire selection if it overlaps region [from, to]
+    if ( (selBottomRight >= (from+scr_TL)) && (selTopLeft <= (to+scr_TL)) )
+        clearSelection();
+}
+
+void Screen::displayCharacter(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 < cuX+w)
+    {
+        screenLines[cuY].resize(cuX+w);
+    }
+
+    if (getMode(MODE_Insert)) insertChars(w);
+
+    lastPos = loc(cuX,cuY);
+
+    // check if selection is still valid.
+    checkSelection(lastPos, lastPos);
+
+    Character& currentChar = screenLines[cuY][cuX];
+
+    currentChar.character = c;
+    currentChar.foregroundColor = effectiveForeground;
+    currentChar.backgroundColor = effectiveBackground;
+    currentChar.rendition = effectiveRendition;
+
+    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 = effectiveForeground;
+        ch.backgroundColor = effectiveBackground;
+        ch.rendition = effectiveRendition;
+
+        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()
+{
+    _scrolledLines = 0;
+}
+
+void Screen::scrollUp(int n)
+{
+    if (n == 0) n = 1; // Default
+    if (_topMargin == 0) addHistLine(); // history.history
+    scrollUp(_topMargin, n);
+}
+
+QRect Screen::lastScrolledRegion() const
+{
+    return _lastScrolledRegion;
+}
+
+void Screen::scrollUp(int from, int n)
+{
+    if (n <= 0 || from + n > _bottomMargin) return;
+
+    _scrolledLines -= n;
+    _lastScrolledRegion = QRect(0,_topMargin,columns-1,(_bottomMargin-_topMargin));
+
+    //FIXME: make sure `topMargin', `bottomMargin', `from', `n' is in bounds.
+    moveImage(loc(0,from),loc(0,from+n),loc(columns-1,_bottomMargin));
+    clearImage(loc(0,_bottomMargin-n+1),loc(columns-1,_bottomMargin),' ');
+}
+
+void Screen::scrollDown(int n)
+{
+    if (n == 0) n = 1; // Default
+    scrollDown(_topMargin, n);
+}
+
+void Screen::scrollDown(int from, int n)
+{
+    _scrolledLines += n;
+
+    //FIXME: make sure `topMargin', `bottomMargin', `from', `n' is in bounds.
+    if (n <= 0) 
+        return;
+    if (from > _bottomMargin) 
+        return;
+    if (from + n > _bottomMargin) 
+        n = _bottomMargin - from;
+    moveImage(loc(0,from+n),loc(0,from),loc(columns-1,_bottomMargin-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) ? _topMargin : 0) ));
+}
+
+void Screen::home()
+{
+    cuX = 0;
+    cuY = 0;
+}
+
+void Screen::toStartOfLine()
+{
+    cuX = 0;
+}
+
+int Screen::getCursorX() const
+{
+    return cuX;
+}
+
+int Screen::getCursorY() const
+{
+    return cuY;
+}
+
+void Screen::clearImage(int loca, int loce, char c)
+{ 
+    int scr_TL=loc(0,history->getLines());
+    //FIXME: check positions
+
+    //Clear entire selection if it overlaps region to be moved...
+    if ( (selBottomRight > (loca+scr_TL) )&&(selTopLeft < (loce+scr_TL)) )
+    {
+        clearSelection();
+    }
+
+    int topLine = loca/columns;
+    int bottomLine = loce/columns;
+
+    Character clearCh(c,currentForeground,currentBackground,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;
+        }
+    }
+}
+
+void Screen::moveImage(int dest, int sourceBegin, int sourceEnd)
+{
+    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 (selBegin != -1)
+    {
+        bool beginIsTL = (selBegin == selTopLeft);
+        int diff = dest - sourceBegin; // Scroll by this amount
+        int scr_TL=loc(0,history->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 ((selTopLeft >= srca) && (selTopLeft <= srce))
+            selTopLeft += diff;
+        else if ((selTopLeft >= desta) && (selTopLeft <= deste))
+            selBottomRight = -1; // Clear selection (see below)
+
+        if ((selBottomRight >= srca) && (selBottomRight <= srce))
+            selBottomRight += diff;
+        else if ((selBottomRight >= desta) && (selBottomRight <= deste))
+            selBottomRight = -1; // Clear selection (see below)
+
+        if (selBottomRight < 0)
+        {
+            clearSelection();
+        }
+        else
+        {
+            if (selTopLeft < 0)
+                selTopLeft = 0;
+        }
+
+        if (beginIsTL)
+            selBegin = selTopLeft;
+        else
+            selBegin = selBottomRight;
+    }
+}
+
+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)
+{
+    currentRendition |= re;
+    updateEffectiveRendition();
+}
+
+void Screen::resetRendition(int re)
+{
+    currentRendition &= ~re;
+    updateEffectiveRendition();
+}
+
+void Screen::setDefaultRendition()
+{
+    setForeColor(COLOR_SPACE_DEFAULT,DEFAULT_FORE_COLOR);
+    setBackColor(COLOR_SPACE_DEFAULT,DEFAULT_BACK_COLOR);
+    currentRendition   = DEFAULT_RENDITION;
+    updateEffectiveRendition();
+}
+
+void Screen::setForeColor(int space, int color)
+{
+    currentForeground = CharacterColor(space, color);
+
+    if ( currentForeground.isValid() ) 
+        updateEffectiveRendition();
+    else 
+        setForeColor(COLOR_SPACE_DEFAULT,DEFAULT_FORE_COLOR);
+}
+
+void Screen::setBackColor(int space, int color)
+{
+    currentBackground = CharacterColor(space, color);
+
+    if ( currentBackground.isValid() ) 
+        updateEffectiveRendition();
+    else
+        setBackColor(COLOR_SPACE_DEFAULT,DEFAULT_BACK_COLOR);
+}
+
+void Screen::clearSelection() 
+{
+    selBottomRight = -1;
+    selTopLeft = -1;
+    selBegin = -1;
+}
+
+void Screen::getSelectionStart(int& column , int& line) const
+{
+    if ( selTopLeft != -1 )
+    {
+        column = selTopLeft % columns;
+        line = selTopLeft / columns; 
+    }
+    else
+    {
+        column = cuX + getHistLines();
+        line = cuY + getHistLines();
+    }
+}
+void Screen::getSelectionEnd(int& column , int& line) const
+{
+    if ( selBottomRight != -1 )
+    {
+        column = selBottomRight % columns;
+        line = selBottomRight / columns;
+    }
+    else
+    {
+        column = cuX + getHistLines();
+        line = cuY + getHistLines();
+    } 
+}
+void Screen::setSelectionStart(const int x, const int y, const bool mode)
+{
+    selBegin = loc(x,y); 
+    /* FIXME, HACK to correct for x too far to the right... */
+    if (x == columns) selBegin--;
+
+    selBottomRight = selBegin;
+    selTopLeft = selBegin;
+    blockSelectionMode = mode;
+}
+
+void Screen::setSelectionEnd( const int x, const int y)
+{
+    if (selBegin == -1) 
+        return;
+
+    int endPos =  loc(x,y); 
+
+    if (endPos < selBegin)
+    {
+        selTopLeft = endPos;
+        selBottomRight = selBegin;
+    }
+    else
+    {
+        /* FIXME, HACK to correct for x too far to the right... */
+        if (x == columns) 
+            endPos--;
+
+        selTopLeft = selBegin;
+        selBottomRight = endPos;
+    }
+
+    // Normalize the selection in column mode
+    if (blockSelectionMode)
+    {
+        int topRow = selTopLeft / columns;
+        int topColumn = selTopLeft % columns;
+        int bottomRow = selBottomRight / columns;
+        int bottomColumn = selBottomRight % columns;
+
+        selTopLeft = loc(qMin(topColumn,bottomColumn),topRow);
+        selBottomRight = loc(qMax(topColumn,bottomColumn),bottomRow);
+    }
+}
+
+bool Screen::isSelected( const int x,const int y) const
+{
+    bool columnInSelection = true;
+    if (blockSelectionMode)
+    {
+        columnInSelection = x >= (selTopLeft % columns) &&
+            x <= (selBottomRight % columns);
+    }
+
+    int pos = loc(x,y);
+    return pos >= selTopLeft && pos <= selBottomRight && columnInSelection;
+}
+
+QString Screen::selectedText(bool preserveLineBreaks) const
+{
+    QString result;
+    QTextStream stream(&result, QIODevice::ReadWrite);
+
+    PlainTextDecoder decoder;
+    decoder.begin(&stream);
+    writeSelectionToStream(&decoder , preserveLineBreaks);
+    decoder.end();
+
+    return result;
+}
+
+bool Screen::isSelectionValid() const
+{
+    return selTopLeft >= 0 && selBottomRight >= 0;
+}
+
+void Screen::writeSelectionToStream(TerminalCharacterDecoder* decoder , 
+        bool preserveLineBreaks) const
+{
+    if (!isSelectionValid())
+        return;
+    writeToStream(decoder,selTopLeft,selBottomRight,preserveLineBreaks);
+}
+
+void Screen::writeToStream(TerminalCharacterDecoder* decoder, 
+        int startIndex, int endIndex,
+        bool preserveLineBreaks) const
+{
+    int top = startIndex / columns;    
+    int left = startIndex % columns;
+
+    int bottom = endIndex / columns;
+    int right = endIndex % columns;
+
+    Q_ASSERT( top >= 0 && left >= 0 && bottom >= 0 && right >= 0 );
+
+    for (int y=top;y<=bottom;y++)
+    {
+        int start = 0;
+        if ( y == top || blockSelectionMode ) start = left;
+
+        int count = -1;
+        if ( y == bottom || blockSelectionMode ) count = right - start + 1;
+
+        const bool appendNewLine = ( y != bottom );
+        int copied = copyLineToStream( y,
+                start,
+                count,
+                decoder, 
+                appendNewLine,
+                preserveLineBreaks );
+
+        // if the selection goes beyond the end of the last line then
+        // append a new line character.
+        //
+        // this makes it possible to 'select' a trailing new line character after
+        // the text on a line.  
+        if ( y == bottom && 
+                copied < count    )
+        {
+            Character newLineChar('\n');
+            decoder->decodeLine(&newLineChar,1,0);
+        }
+    }    
+}
+
+int Screen::copyLineToStream(int line , 
+        int start, 
+        int count,
+        TerminalCharacterDecoder* decoder,
+        bool appendNewLine,
+        bool preserveLineBreaks) const
+{
+    //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 < history->getLines())
+    {
+        const int lineLength = history->getLineLen(line);
+
+        // ensure that start position is before end of line
+        start = qMin(start,qMax(0,lineLength-1));
+
+        // retrieve line from history buffer.  It is assumed
+        // that the history buffer does not store trailing white space
+        // at the end of the line, so it does not need to be trimmed here 
+        if (count == -1)
+        {
+            count = lineLength-start;
+        }
+        else
+        {
+            count = qMin(start+count,lineLength)-start;
+        }
+
+        // safety checks
+        assert( start >= 0 );
+        assert( count >= 0 );    
+        assert( (start+count) <= history->getLineLen(line) );
+
+        history->getCells(line,start,count,characterBuffer);
+
+        if ( history->isWrappedLine(line) )
+            currentLineProperties |= LINE_WRAPPED;
+    }
+    else
+    {
+        if ( count == -1 )
+            count = columns - start;
+
+        assert( count >= 0 );
+
+        const int screenLine = line-history->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]; 
+    }
+
+    // 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 );
+
+    return count;
+}
+
+void Screen::writeLinesToStream(TerminalCharacterDecoder* decoder, int fromLine, int toLine) const
+{
+    writeToStream(decoder,loc(0,fromLine),loc(columns-1,toLine));
+}
+
+void Screen::addHistLine()
+{
+    // add line to history buffer
+    // we have to take care about scrolling, too...
+
+    if (hasScroll())
+    {
+        int oldHistLines = history->getLines();
+
+        history->addCellsVector(screenLines[0]);
+        history->addLine( lineProperties[0] & LINE_WRAPPED );
+
+        int newHistLines = history->getLines();
+
+        bool beginIsTL = (selBegin == selTopLeft);
+
+        // 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 (selBegin != -1)
+            {
+                selTopLeft += columns;
+                selBottomRight += columns;
+            }
+        }
+
+        if (selBegin != -1)
+        {
+            // Scroll selection in history up
+            int top_BR = loc(0, 1+newHistLines);
+
+            if (selTopLeft < top_BR)
+                selTopLeft -= columns;
+
+            if (selBottomRight < top_BR)
+                selBottomRight -= columns;
+
+            if (selBottomRight < 0)
+                clearSelection();
+            else
+            {
+                if (selTopLeft < 0)
+                    selTopLeft = 0;
+            }
+
+            if (beginIsTL)
+                selBegin = selTopLeft;
+            else
+                selBegin = selBottomRight;
+        }
+    }
+
+}
+
+int Screen::getHistLines() const
+{
+    return history->getLines();
+}
+
+void Screen::setScroll(const HistoryType& t , bool copyPreviousScroll)
+{
+    clearSelection();
+
+    if ( copyPreviousScroll )
+        history = t.scroll(history);
+    else
+    {
+        HistoryScroll* oldScroll = history;
+        history = t.scroll(0);
+        delete oldScroll;
+    }
+}
+
+bool Screen::hasScroll() const
+{
+    return history->hasScroll();
+}
+
+const HistoryType& Screen::getScroll() const
+{
+    return history->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//src/Screen.h
@@ -0,0 +1,670 @@
+/*
+    This file is part of Konsole, KDE's terminal.
+
+    Copyright 2007-2008 by Robert Knight <robertknight@gmail.com>
+    Copyright 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
+
+    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
+
+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 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.  The cursor will stop at the 
+     * top margin.
+     */
+    void cursorUp(int n);
+    /** 
+     * Move the cursor down by @p n lines.  The cursor will stop at the
+     * bottom margin.
+     */
+    void cursorDown(int n);
+    /** 
+     * Move the cursor to the left by @p n columns.
+     * The cursor will stop at the first column.
+     */
+    void cursorLeft(int n);
+    /** 
+     * Move the cursor to the right by @p n columns.
+     * The cursor will stop at the right-most column.
+     */
+    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.  Equivalent to calling Return() followed by index()
+     */
+    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 toStartOfLine();
+    /** 
+     * 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 tab(int n = 1);
+    /** Moves the cursor @p n tab-stops to the left. */
+    void backtab(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 appearance (text color and style) of the cursor. 
+     * It can be restored by calling restoreCursor() 
+     */ 
+    void saveCursor();
+    /** Restores the position and appearance 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 appearance 
+     * of characters on the screen.
+     *
+     * @see Character::rendition
+     */  
+    void setRendition(int rendition);
+    /**
+     * Disables the given @p rendition flag.  Rendition flags control the appearance
+     * 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;
+   
+    /** Clear the entire screen and move the cursor to the home position.
+     * Equivalent to calling clearEntireScreen() followed by home().
+     */
+    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 displayCharacter(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.
+     *
+     * The top and bottom margins are reset to the top and bottom of the new 
+     * screen size.  Tab stops are also reset and the current selection is
+     * cleared.
+     */
+    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() const   
+    { return lines; }
+    /** Return the number of columns. */
+    int getColumns() const 
+    { return columns; }
+    /** Return the number of lines in the history buffer. */
+    int getHistLines() const;
+    /** 
+     * 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() const;
+    /** 
+     * Returns true if this screen keeps lines that are scrolled off the screen
+     * in a history buffer.
+     */
+    bool hasScroll() const;
+
+    /** 
+     * 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 blockSelectionMode True if the selection is in column mode.
+     */
+    void setSelectionStart(const int column, const int line, const bool blockSelectionMode);
+    
+    /**
+     * 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) const;
+    
+    /**
+     * Retrieves the end of the selection or the cursor position if there
+     * is no selection.
+     */
+    void getSelectionEnd(int& column , int& line) const;
+
+    /** Clears the current selection */
+    void clearSelection();
+
+    /** 
+      *  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) const;
+        
+    /**
+     * Copies part of the output to a stream.
+     *
+     * @param decoder A decoder which converts terminal characters into text
+     * @param fromLine The first line in the history to retrieve
+     * @param toLine The last line in the history to retrieve
+     */
+    void writeLinesToStream(TerminalCharacterDecoder* decoder, int fromLine, int toLine) const;
+
+    /**
+     * 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 converts 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) const;
+
+    /**
+     * Checks if the text between from and to is inside the current
+     * selection. If this is the case, the selection is cleared. The
+     * from and to are coordinates in the current viewable window.
+     * The loc(x,y) macro can be used to generate these values from a
+     * column,line pair.
+     *
+     * @param from The start of the area to check.
+     * @param to The end of the area to check
+     */
+    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.  Returns the number of lines actually copied,
+    //which may be less than 'count' if (start+count) is more than the number of characters on
+    //the line 
+    //
+    //line - the line number to copy, from 0 (the earliest line in the history) up to 
+    //         history->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 converts terminal characters (an Character array) into text
+    //appendNewLine - if true a new line character (\n) is appended to the end of the line
+    int  copyLineToStream(int line, 
+                          int start, 
+                          int count, 
+                          TerminalCharacterDecoder* decoder,
+                          bool appendNewLine,
+                          bool preserveLineBreaks) const;
+    
+    //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.
+    //
+    //NOTE: moveImage() can only move whole lines
+    void moveImage(int dest, int sourceBegin, int sourceEnd);
+    // scroll up 'i' lines in current region, clearing the bottom 'i' lines 
+    void scrollUp(int from, int i);
+    // scroll down 'i' lines in current region, clearing the top 'i' lines
+    void scrollDown(int from, int i);
+
+    void addHistLine();
+
+    void initTabStops();
+
+    void updateEffectiveRendition();
+    void reverseRendition(Character& p) const;
+
+    bool isSelectionValid() const;
+    // copies text from 'startIndex' to 'endIndex' to a stream
+    // startIndex and endIndex are positions generated using the loc(x,y) macro
+    void writeToStream(TerminalCharacterDecoder* decoder, int startIndex, 
+                       int endIndex, bool preserveLineBreaks = true) 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* history;
+    
+    // cursor location
+    int cuX;
+    int cuY;
+
+    // cursor color and rendition info
+    CharacterColor currentForeground;
+    CharacterColor currentBackground;
+    quint8 currentRendition; 
+
+    // margins ----------------
+    int _topMargin;
+    int _bottomMargin;
+
+    // states ----------------
+    int currentModes[MODES_SCREEN];
+    int savedModes[MODES_SCREEN];
+
+    // ----------------------------
+
+    QBitArray tabStops;
+
+    // selection -------------------
+    int selBegin; // The first location selected.
+    int selTopLeft;    // TopLeft Location.
+    int selBottomRight;    // Bottom Right Location.
+    bool blockSelectionMode;  // Column selection mode
+
+    // effective colors and rendition ------------
+    CharacterColor effectiveForeground; // These are derived from
+    CharacterColor effectiveBackground; // the cu_* variables above
+    quint8 effectiveRendition;          // to speed up operation
+
+    class SavedState  
+    {
+    public:
+        SavedState()
+        : cursorColumn(0),cursorLine(0),rendition(0) {}
+
+        int cursorColumn;
+        int cursorLine;
+        quint8 rendition;
+        CharacterColor foreground;
+        CharacterColor background;
+    };
+    SavedState savedState;
+        
+    // last position where we added a character
+    int lastPos;
+
+    static Character defaultChar;
+};
+
+#endif // SCREEN_H
new file mode 100644
--- /dev/null
+++ b/gui//src/ScreenWindow.cpp
@@ -0,0 +1,292 @@
+/*
+    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"
+
+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(); 
+}
new file mode 100644
--- /dev/null
+++ b/gui//src/ScreenWindow.h
@@ -0,0 +1,251 @@
+/*
+    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"
+
+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//src/Session.cpp
@@ -0,0 +1,1209 @@
+/*
+    This file is part of Konsole
+
+    Copyright 2006-2008 by Robert Knight <robertknight@gmail.com>
+    Copyright 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
+    Copyright 2009 by Thomas Dreibholz <dreibh@iem.uni-due.de>
+
+    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>
+#include <signal.h>
+
+// Qt
+#include <QtGui/QApplication>
+#include <QtCore/QByteRef>
+#include <QtCore/QDir>
+#include <QtCore/QFile>
+#include <QtCore/QRegExp>
+#include <QtCore/QStringList>
+#include <QtCore/QDate>
+
+#include "kprocess.h"
+#include "kptydevice.h"
+
+#include "ProcessInfo.h"
+#include "Pty.h"
+#include "TerminalDisplay.h"
+#include "ShellCommand.h"
+#include "Vt102Emulation.h"
+
+int Session::lastSessionId = 0;
+
+// HACK This is copied out of QUuid::createUuid with reseeding forced.
+// Required because color schemes repeatedly seed the RNG...
+// ...with a constant.
+QUuid createUuid()
+{
+    static const int intbits = sizeof(int)*8;
+    static int randbits = 0;
+    if (!randbits)
+    {
+        int max = RAND_MAX;
+        do { ++randbits; } while ((max=max>>1));
+    }
+
+    qsrand(uint(QDateTime::currentDateTime().toTime_t()));
+    qrand(); // Skip first
+
+    QUuid result;
+    uint *data = &(result.data1);
+    int chunks = 16 / sizeof(uint);
+    while (chunks--) {
+        uint randNumber = 0;
+        for (int filled = 0; filled < intbits; filled += randbits)
+            randNumber |= qrand()<<filled;
+         *(data+chunks) = randNumber;
+    }
+
+    result.data4[0] = (result.data4[0] & 0x3F) | 0x80;        // UV_DCE
+    result.data3 = (result.data3 & 0x0FFF) | 0x4000;        // UV_Random
+
+    return result;
+}
+
+Session::Session(QObject* parent) :
+   QObject(parent)
+   , _shellProcess(0)
+   , _emulation(0)
+   , _monitorActivity(false)
+   , _monitorSilence(false)
+   , _notifiedActivity(false)
+   , _autoClose(true)
+   , _wantedClose(false)
+   , _silenceSeconds(10)
+   , _addToUtmp(true)  
+   , _flowControl(true)
+   , _fullScripting(false)
+   , _sessionId(0)
+   , _sessionProcessInfo(0)
+   , _foregroundProcessInfo(0)
+   , _foregroundPid(0)
+   //, _zmodemBusy(false)
+   //, _zmodemProc(0)
+   //, _zmodemProgress(0)
+   , _hasDarkBackground(false)
+{
+    _uniqueIdentifier = createUuid();
+
+    //prepare DBus communication
+    //new SessionAdaptor(this);
+    _sessionId = ++lastSessionId;
+    
+    // JPS: commented out for lack of DBUS support by default on OSX
+    //QDBusConnection::sessionBus().registerObject(QLatin1String("/Sessions/")+QString::number(_sessionId), this);
+
+    //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&)) );
+    connect( _emulation, SIGNAL(flowControlKeyPressed(bool)) , this, 
+             SLOT(updateFlowControlState(bool)) );
+
+    //create new teletype for I/O with shell process
+    openTeletype(-1);
+
+    //setup timer for monitoring session activity
+    _monitorTimer = new QTimer(this);
+    _monitorTimer->setSingleShot(true);
+    connect(_monitorTimer, SIGNAL(timeout()), this, SLOT(monitorTimerDone()));
+}
+
+void Session::openTeletype(int fd)
+{
+    if (_shellProcess && isRunning())
+    {
+        //kWarning() << "Attempted to open teletype in a running session.";
+        return;
+    }
+
+    delete _shellProcess;
+
+    if (fd < 0)
+        _shellProcess = new Pty();
+    else
+        _shellProcess = new Pty(fd);
+
+    _shellProcess->setUtf8Mode(_emulation->utf8());
+
+    //connect teletype to emulation backend
+    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(finished(int,QProcess::ExitStatus)), this, SLOT(done(int)) );
+    connect( _emulation,SIGNAL(imageSizeChanged(int,int)),this,SLOT(updateWindowSize(int,int)) );
+}
+
+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->state() == QProcess::Running;
+}
+
+void Session::setCodec(QTextCodec* codec)
+{
+    emulation()->setCodec(codec);
+}
+
+bool Session::setCodec(QByteArray name)
+{
+    QTextCodec *codec = QTextCodec::codecForName(name);
+    if (codec) {
+        setCodec(codec);
+        return true;
+    }
+    return false;
+}
+
+QByteArray Session::codec()
+{
+    return _emulation->codec()->name();
+}
+
+void Session::setProgram(const QString& program)
+{
+    _program = ShellCommand::expand(program);
+}
+void Session::setInitialWorkingDirectory(const QString& dir)
+{
+  //_initialWorkingDir = KShell::tildeExpand(ShellCommand::expand(dir));
+  _initialWorkingDir = ShellCommand::expand(dir);
+}
+void Session::setArguments(const QStringList& arguments)
+{
+    _arguments = ShellCommand::expand(arguments);
+}
+
+QString Session::currentWorkingDirectory()
+{
+    // only returned cached value
+    if (_currentWorkingDir.isEmpty()) updateWorkingDirectory();
+    return _currentWorkingDir;
+}
+ProcessInfo* Session::updateWorkingDirectory()
+{
+    ProcessInfo *process = getProcessInfo();
+    _currentWorkingDir = process->validCurrentDir();
+    return process;
+}
+
+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*)) );
+}
+
+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();
+    }
+}
+
+QString Session::checkProgram(const QString& program) const
+{
+  // 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.isEmpty())
+      return QString();
+
+  // 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 = qgetenv("SHELL");
+  if ( exec.isEmpty() )
+        exec = "/bin/sh";
+  return program;
+}
+
+void Session::terminalWarning(const QString& message)
+{
+  static const QByteArray warningText = QByteArray("@info:shell Alert the user with red color text");
+    QByteArray messageText = message.toLocal8Bit();
+
+    static const char redPenOn[] = "\033[1m\033[31m";
+    static const char redPenOff[] = "\033[0m";
+
+    _emulation->receiveData(redPenOn,strlen(redPenOn));
+    _emulation->receiveData("\n\r\n\r",4);
+    _emulation->receiveData(warningText.constData(),strlen(warningText.constData()));
+    _emulation->receiveData(messageText.constData(),strlen(messageText.constData()));
+    _emulation->receiveData("\n\r\n\r",4);
+    _emulation->receiveData(redPenOff,strlen(redPenOff));
+}
+
+QString Session::shellSessionId() const
+{
+    QString friendlyUuid(_uniqueIdentifier.toString());
+    friendlyUuid.remove('-').remove('{').remove('}');
+
+    return friendlyUuid;
+}
+
+void Session::run()
+{
+  //check that everything is in place to run the session
+  if (_program.isEmpty())
+  {
+      //kWarning() << "Session::run() - program to run not set.";
+  }
+  if (_arguments.isEmpty())
+  {
+      //kWarning() << "Session::run() - no command line arguments specified.";
+  }
+  if (_uniqueIdentifier.isNull())
+  {
+      _uniqueIdentifier = createUuid();
+  }
+
+  const int CHOICE_COUNT = 3;
+  QString programs[CHOICE_COUNT] = {_program,qgetenv("SHELL"),"/bin/sh"};
+  QString exec;
+  int choice = 0;
+  while (choice < CHOICE_COUNT)
+  {
+    exec = checkProgram(programs[choice]);
+    if (exec.isEmpty())
+        choice++;
+    else
+        break;
+  }
+
+  // if a program was specified via setProgram(), but it couldn't be found, print a warning
+  if (choice != 0 && choice < CHOICE_COUNT && !_program.isEmpty())
+  {
+    QString msg;
+    QTextStream msgStream(&msg);
+    msgStream << "Could not find '" << _program << "', starting '" << exec << "' instead. Please check your profile settings.";
+    terminalWarning(msg);
+    //terminalWarning(i18n("Could not find '%1', starting '%2' instead.  Please check your profile settings.",_program.toLatin1().data(),exec.toLatin1().data())); 
+  }
+  // if none of the choices are available, print a warning
+  else if (choice == CHOICE_COUNT)
+  {
+      terminalWarning(QString("Could not find an interactive shell to start."));
+      return;
+  }
+  
+  // if no arguments are specified, fall back to program name
+  QStringList arguments = _arguments.join(QChar(' ')).isEmpty() ?
+                                                   QStringList() << exec : _arguments;
+
+  // JPS: commented out for lack of DBUS support by default on OSX
+  QString dbusService = ""; //QDBusConnection::sessionBus().baseService();
+  if (!_initialWorkingDir.isEmpty())
+    _shellProcess->setWorkingDirectory(_initialWorkingDir);
+  else
+    _shellProcess->setWorkingDirectory(QDir::homePath());
+
+  _shellProcess->setFlowControlEnabled(_flowControl);
+  _shellProcess->setErase(_emulation->eraseChar());
+
+  // 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";
+  _environment << backgroundColorHint;
+  _environment << QString("SHELL_SESSION_ID=%1").arg(shellSessionId());
+
+  int result = _shellProcess->start(exec,
+                                  arguments,
+                                  _environment,
+                                  windowId(),
+                                  _addToUtmp,
+                                  dbusService,
+                                  (QLatin1String("/Sessions/") +
+                                   QString::number(_sessionId)));
+
+  if (result < 0)
+  {
+    QString msg;
+    QTextStream msgStream(&msg);
+    msgStream << QString("Could not start program '") << exec << QString("' with arguments '") << arguments.join(" ") << QString("'.");
+    terminalWarning (msg);
+    //      terminalWarning(i18n("Could not start program '%1' with arguments '%2'.", exec.toLatin1().data(), arguments.join(" ").toLatin1().data()));
+    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;
+
+    if ((what == IconNameAndWindowTitle) || (what == WindowTitle)) 
+    {
+           if ( _userTitle != caption ) {
+            _userTitle = caption;
+            modified = true;
+        }
+    }
+
+    if ((what == IconNameAndWindowTitle) || (what == IconName))
+    {
+        if ( _iconText != caption ) {
+               _iconText = caption;
+            modified = true;
+        }
+    }
+
+    if (what == TextColor || what == BackgroundColor) 
+    {
+      QString colorString = caption.section(';',0,0);
+      QColor color = QColor(colorString);
+      if (color.isValid())
+      {
+          if (what == TextColor)
+                  emit changeForegroundColorRequest(color);
+          else
+                  emit changeBackgroundColorRequest(color);
+      }
+    }
+
+    if (what == SessionName) 
+    {
+        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 == ProfileChange) 
+    {
+        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", i18n("Silence in session '%1'", _nameTitle)propagateSize, QPixmap(),
+    //                QApplication::activeWindow(),
+    //                KNotification::CloseWhenWidgetActivated);
+    emit stateChanged(NOTIFYSILENCE);
+  }
+  else
+  {
+    emit stateChanged(NOTIFYNORMAL);
+  }
+
+  _notifiedActivity=false;
+}
+void Session::updateFlowControlState(bool suspended)
+{
+    if (suspended)
+    {
+        if (flowControlEnabled())
+        {
+            foreach(TerminalDisplay* display,_views)
+            {
+                if (display->flowControlWarningEnabled())
+                    display->outputSuspended(true);
+            }
+        }
+    } 
+    else
+    {
+        foreach(TerminalDisplay* display,_views)
+            display->outputSuspended(false);
+    }   
+}
+void Session::activityStateSet(int state)
+{
+  if (state==NOTIFYBELL)
+  {
+      emit bellRequest(QString("Bell in session '%1'").arg(_nameTitle.toLatin1().data()));
+  }
+  else if (state==NOTIFYACTIVITY)
+  {
+    if (_monitorSilence) {
+      _monitorTimer->start(_silenceSeconds*1000);
+    }
+
+    if ( _monitorActivity ) {
+      //FIXME:  See comments in Session::monitorTimerDone()
+      if (!_notifiedActivity) {
+        //KNotification::event("Activity", i18n("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::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() );
+            view->processFilters();
+        }
+    }
+
+    // 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 );
+    }
+}
+void Session::updateWindowSize(int lines, int columns)
+{
+    Q_ASSERT(lines > 0 && columns > 0);
+    _shellProcess->setWindowSize(lines,columns);
+}
+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::kill(int signal)
+{
+    int result = ::kill(_shellProcess->pid(),signal);    
+    
+    if ( result == 0 )
+    {
+        _shellProcess->waitForFinished();
+        return true;
+    }
+    else
+        return false;
+}
+
+void Session::close()
+{
+  _autoClose = true;
+  _wantedClose = true;
+
+  if (!isRunning() || !kill(SIGHUP))
+  {
+     if (isRunning())
+     {
+        //kWarning() << "Process" << _shellProcess->pid() << "did not respond to SIGHUP";
+
+        // close the pty and wait to see if the process finishes.  If it does,
+        // the done() slot will have been called so we can return.  Otherwise,
+        // emit the finished() signal regardless
+        _shellProcess->pty()->close();
+        if (_shellProcess->waitForFinished(3000))
+            return;
+
+        //kWarning() << "Unable to kill process" << _shellProcess->pid();
+     }
+
+     // Forced close.
+     QTimer::singleShot(1, this, SIGNAL(finished()));
+  }
+}
+
+void Session::sendText(const QString &text) const
+{
+  _emulation->sendText(text);
+}
+
+void Session::sendMouseEvent(int buttons, int column, int line, int eventType)
+{
+    _emulation->sendMouseEvent(buttons, column, line, eventType);
+}
+
+Session::~Session()
+{
+  if (_foregroundProcessInfo)
+      delete _foregroundProcessInfo;
+  if (_sessionProcessInfo)
+      delete _sessionProcessInfo;
+  delete _emulation;
+  delete _shellProcess;
+  //delete _zmodemProc;
+}
+
+void Session::done(int exitStatus)
+{
+  if (!_autoClose)
+  {
+    _userTitle = QString("@info:shell This session is done");
+    emit titleChanged();
+    return;
+  }
+
+  QString message;
+  QTextStream msgStream(&message);
+  if (!_wantedClose || exitStatus != 0)
+  {
+    if (_shellProcess->exitStatus() == QProcess::NormalExit)
+    {
+      msgStream << "Program '" << _program << "' exited with statis " << exitStatus << ".";
+      //message = i18n("Program '%1' exited with status %2.", _program.toLatin1().data(), exitStatus);
+
+    }
+    else
+    {
+      msgStream << "Program '" << _program << "' crashed.";
+      //message = i18n("Program '%1' crashed.", _program.toLatin1().data());
+	
+    }
+
+    //FIXME: See comments in Session::monitorTimerDone()
+    //KNotification::event("Finished", message , QPixmap(),
+    //                     QApplication::activeWindow(),
+    //                     KNotification::CloseWhenWidgetActivated);
+  }
+
+  if ( !_wantedClose && _shellProcess->exitStatus() != QProcess::NormalExit )
+      terminalWarning(message);
+  else
+        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();
+}
+
+ProcessInfo* Session::getProcessInfo()
+{
+    ProcessInfo* process;
+
+    if (isForegroundProcessActive())
+        process = _foregroundProcessInfo;
+    else
+    {
+        updateSessionProcessInfo();
+        process = _sessionProcessInfo;
+    }
+
+    return process;
+}
+
+void Session::updateSessionProcessInfo()
+{
+    Q_ASSERT(_shellProcess);
+    if (!_sessionProcessInfo)
+    {
+        _sessionProcessInfo = ProcessInfo::newInstance(processId());
+        _sessionProcessInfo->setUserHomeDir();
+    }
+    _sessionProcessInfo->update();
+}
+
+bool Session::updateForegroundProcessInfo()
+{
+    bool valid = (_foregroundProcessInfo != 0);
+
+    // has foreground process changed?
+    Q_ASSERT(_shellProcess);
+    int pid = _shellProcess->foregroundProcessGroup();
+    if (pid != _foregroundPid)
+    {
+        if (valid)
+            delete _foregroundProcessInfo;
+        _foregroundProcessInfo = ProcessInfo::newInstance(pid);
+        _foregroundPid = pid;
+        valid = true;
+    }
+
+    if (valid)
+    {
+        _foregroundProcessInfo->update();
+        valid = _foregroundProcessInfo->isValid();
+    }
+
+    return valid;
+}
+
+bool Session::isRemote()
+{
+    ProcessInfo* process = getProcessInfo();
+
+    bool ok = false;
+    return ( process->name(&ok) == "ssh" && ok );
+}
+
+QString Session::getDynamicTitle()
+{
+    // update current directory from process
+    ProcessInfo* process = updateWorkingDirectory();
+
+    // format tab titles using process info
+    bool ok = false;
+    QString title;
+    if ( process->name(&ok) == "ssh" && ok )
+    {
+        SSHProcessInfo sshInfo(*process);
+        title = sshInfo.format(tabTitleFormat(Session::RemoteTabTitle));
+    }
+    else
+        title = process->format(tabTitleFormat(Session::LocalTabTitle));
+
+    return title;
+}
+
+void Session::setIconName(const QString& iconName)
+{
+    if ( iconName != _iconName )
+    {
+        _iconName = iconName;
+        emit titleChanged();
+    }
+}
+
+void Session::setIconText(const QString& iconText)
+{
+  _iconText = 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)
+{
+  _flowControl = enabled;
+
+  if (_shellProcess)  
+    _shellProcess->setFlowControlEnabled(_flowControl);
+  emit flowControlEnabledChanged(enabled);
+}
+bool Session::flowControlEnabled() const
+{
+    if (_shellProcess)
+            return _shellProcess->flowControlEnabled();
+    else
+            return _flowControl;
+}
+
+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::processId() const
+{
+    return _shellProcess->pid();
+}
+
+void Session::setTitle(int role , const QString& title)
+{
+    switch (role) {
+    case (0):
+        this->setTitle(Session::NameRole, title);
+        break;
+    case (1):
+        this->setTitle(Session::DisplayedTitleRole, title);
+        break;
+    }
+}
+
+QString Session::title(int role) const
+{
+    switch (role) {
+    case (0):
+        return this->title(Session::NameRole);
+    case (1):
+        return this->title(Session::DisplayedTitleRole);
+    default:
+        return QString();
+    }
+}
+
+void Session::setTabTitleFormat(int context , const QString& format)
+{
+    switch (context) {
+    case (0):
+        this->setTabTitleFormat(Session::LocalTabTitle, format);
+        break;
+    case (1):
+        this->setTabTitleFormat(Session::RemoteTabTitle, format);
+        break;
+    }
+}
+
+QString Session::tabTitleFormat(int context) const
+{
+    switch (context) {
+    case (0):
+        return this->tabTitleFormat(Session::LocalTabTitle);
+    case (1):
+        return this->tabTitleFormat(Session::RemoteTabTitle);
+    default:
+        return QString();
+    }
+}
+
+int Session::foregroundProcessId()
+{
+    int pid;
+
+    bool ok = false;
+    pid = getProcessInfo()->pid(&ok);
+    if (!ok)
+        pid = -1;
+
+    return pid;
+}
+
+bool Session::isForegroundProcessActive()
+{
+    // foreground process info is always updated after this
+    return updateForegroundProcessInfo() && (processId() != _foregroundPid);
+}
+
+QString Session::foregroundProcessName()
+{
+    QString name;
+
+    if (updateForegroundProcessInfo()) 
+    {
+        bool ok = false;
+        name = _foregroundProcessInfo->name(&ok);
+        if (!ok)
+            name.clear();
+    }
+
+    return name;
+}
+
+SessionGroup::SessionGroup(QObject* parent)
+    : QObject(parent), _masterMode(0)
+{
+}
+SessionGroup::~SessionGroup()
+{
+}
+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)
+{
+    connect(session,SIGNAL(finished()),this,SLOT(sessionFinished()));
+    _sessions.insert(session,false);
+}
+void SessionGroup::removeSession(Session* session)
+{
+    disconnect(session,SIGNAL(finished()),this,SLOT(sessionFinished()));
+    setMasterStatus(session,false);
+    _sessions.remove(session);
+}
+void SessionGroup::sessionFinished()
+{
+    Session* session = qobject_cast<Session*>(sender());
+    Q_ASSERT(session);
+    removeSession(session);
+}
+void SessionGroup::setMasterMode(int mode)
+{
+   _masterMode = mode;
+}
+QList<Session*> SessionGroup::masters() const
+{
+    return _sessions.keys(true);
+}
+void SessionGroup::setMasterStatus(Session* session , bool master)
+{
+    const bool wasMaster = _sessions[session];
+
+    if (wasMaster == master) {
+        // No status change -> nothing to do.
+        return;
+    }
+    _sessions[session] = master;
+
+    if(master) {
+        connect( session->emulation() , SIGNAL(sendData(const char*,int)) , this,
+                 SLOT(forwardData(const char*,int)) );
+    }
+    else {
+        disconnect( session->emulation() , SIGNAL(sendData(const char*,int)) , this,
+                    SLOT(forwardData(const char*,int)) );
+    }
+}
+void SessionGroup::forwardData(const char* data, int size)
+{
+    static bool _inForwardData = false;
+    if(_inForwardData) {   // Avoid recursive calls among session groups!
+       // A recursive call happens when a master in group A calls forwardData()
+       // in group B. If one of the destination sessions in group B is also a
+       // master of a group including the master session of group A, this would
+       // again call forwardData() in group A, and so on.
+       return;
+    }
+    
+    _inForwardData = true;
+    QListIterator<Session*> iter(_sessions.keys());
+    while(iter.hasNext()) {
+        Session* other = iter.next();
+        if(!_sessions[other]) {
+           other->emulation()->sendString(data, size);
+        }
+    }
+    _inForwardData = false;
+}
+
+
new file mode 100644
--- /dev/null
+++ b/gui//src/Session.h
@@ -0,0 +1,752 @@
+/*
+    This file is part of Konsole, an X terminal.
+
+    Copyright 2007-2008 by Robert Knight <robertknight@gmail.com>
+    Copyright 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
+    Copyright 2009 by Thomas Dreibholz <dreibh@iem.uni-due.de>
+
+    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/QByteRef>
+#include <QtCore/QSize>
+#include <QUuid>
+#include <QWidget>
+
+// Konsole
+#include "History.h"
+
+class KProcess;
+class KUrl;
+class Emulation;
+class Pty;
+class ProcessInfo;
+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
+Q_CLASSINFO("D-Bus Interface", "org.kde.konsole.Session")
+
+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.
+   */
+  explicit Session(QObject* parent = 0);
+  ~Session();
+
+  /** 
+   * Connect to an existing terminal.  When a new Session() is constructed it 
+   * automatically searches for and opens a new teletype.  If you want to 
+   * use an existing teletype (given its file descriptor) call this after
+   * constructing the session.
+   *
+   * Calling openTeletype() while a session is running has no effect.
+   *
+   * @param masterFd The file descriptor of the pseudo-teletype master (See KPtyProcess::KPtyProcess())
+   */
+  void openTeletype(int masterFd);
+
+  /**
+   * Returns true if the session is currently running.  This will be true
+   * after run() has been called successfully.
+   */
+  bool isRunning() 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 unique ID for this session. */
+  int sessionId() 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
+  };
+
+  /**
+   * Returns true if the session currently contains a connection to a 
+   * remote computer.  It currently supports ssh.
+   */
+  bool isRemote();
+
+  /**
+   * 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 );
+
+  /**
+   * Returns the current directory of the foreground process in the session
+   */
+  QString currentWorkingDirectory();
+
+  /**
+   * 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();
+
+  /**
+   * 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
+  };
+
+  /**
+   * 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;
+
+  /** Convenience method used to read the name property.  Returns title(Session::NameRole). */
+  QString nameTitle() const { return title(Session::NameRole); }
+  /** Returns a title generated from tab format and process information. */
+  QString getDynamicTitle();
+
+  /** 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;
+
+  /** Return URL for the session. */
+  //KUrl getUrl();
+
+  /** 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;
+
+  /** 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;
+
+  /** 
+   * Specifies whether a utmp entry should be created for the pty used by this session.
+   * If true, KPty::login() is called when the session is started.
+   */
+  void setAddToUtmp(bool);
+
+  /**
+   * Specifies whether to close the session automatically when the terminal
+   * process terminates.
+   */
+  void setAutoClose(bool b) { _autoClose = b; }
+
+  /** Returns true if the user has started a program in the session. */
+  bool isForegroundProcessActive();
+
+  /** Returns the name of the current foreground process. */
+  QString foregroundProcessName();
+
+  /** 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 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; }
+
+ /** 
+   * Possible values of the @p what parameter for setUserTitle()
+   * See "Operating System Controls" section on http://rtfm.etla.org/xterm/ctlseq.html 
+   */
+  enum UserTitleChange
+  {
+      IconNameAndWindowTitle     = 0,
+    IconName                 = 1,
+    WindowTitle                = 2,
+    TextColor                = 10,
+    BackgroundColor            = 11,
+    SessionName                = 30,
+    ProfileChange            = 50     // this clashes with Xterm's font change command
+  };
+
+  // Sets the text codec used by this sessions terminal emulation.
+  void setCodec(QTextCodec* codec);
+
+  // session management
+  //void saveSession(KConfigGroup& group);
+  //void restoreSession(KConfigGroup& group);
+
+public slots:
+
+  /**
+   * Starts the terminal session.
+   *
+   * This creates the terminal process and connects the teletype to it.
+   */
+  void run();
+
+  /**
+   * Returns the environment of this session as a list of strings like
+   * VARIABLE=VALUE
+   */
+  Q_SCRIPTABLE QStringList environment() const;
+
+  /**
+   * Sets the environment for this session.
+   * @p environment should be a list of strings like
+   * VARIABLE=VALUE
+   */
+  Q_SCRIPTABLE void setEnvironment(const QStringList& environment);
+
+  /**
+   * Closes the terminal session.  This sends a hangup signal
+   * (SIGHUP) to the terminal process and causes the finished()  
+   * signal to be emitted.  If the process does not respond to the SIGHUP signal
+   * then the terminal connection (the pty) is closed and Konsole waits for the 
+   * process to exit.
+   */
+  Q_SCRIPTABLE 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.
+   *
+   * @param what The feature being changed.  Value is one of UserTitleChange
+   * @param caption The text part of the terminal command
+   */
+  void setUserTitle( int what , const QString &caption );
+
+  /**
+   * 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.
+   */
+  Q_SCRIPTABLE void setMonitorActivity(bool);
+
+  /** Returns true if monitoring for activity is enabled. */
+  Q_SCRIPTABLE 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()
+   */
+  Q_SCRIPTABLE void setMonitorSilence(bool);
+
+  /**
+   * Returns true if monitoring for inactivity (silence)
+   * in the session is enabled.
+   */
+  Q_SCRIPTABLE bool isMonitorSilence() const;
+
+  /** See setMonitorSilence() */
+  Q_SCRIPTABLE void setMonitorSilenceSeconds(int seconds);
+
+  /**
+   * Sets whether flow control is enabled for this terminal
+   * session.
+   */
+  Q_SCRIPTABLE void setFlowControlEnabled(bool enabled);
+
+  /** Returns whether flow control is enabled for this terminal session. */
+  Q_SCRIPTABLE bool flowControlEnabled() const;
+
+  /**
+   * Sends @p text to the current foreground terminal program.
+   */
+  Q_SCRIPTABLE void sendText(const QString& text) const;
+
+   /**
+    * Sends a mouse event of type @p eventType emitted by button
+    * @p buttons on @p column/@p line to the current foreground
+    * terminal program
+    */
+   Q_SCRIPTABLE void sendMouseEvent(int buttons, int column, int line, int eventType);
+
+   /**
+   * Returns the process id of the terminal process.
+   * This is the id used by the system API to refer to the process.
+   */
+  Q_SCRIPTABLE 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.
+   */
+  Q_SCRIPTABLE int foregroundProcessId();
+
+  /** Sets the text codec used by this sessions terminal emulation.
+    * Overloaded to accept a QByteArray for convenience since DBus
+    * does not accept QTextCodec directky.
+    */
+  Q_SCRIPTABLE bool setCodec(QByteArray codec);
+
+  /** Returns the codec used to decode incoming characters in this
+   * terminal emulation
+   */
+  Q_SCRIPTABLE QByteArray codec();
+
+  /** Sets the session's title for the specified @p role to @p title.
+   *  This is an overloaded member function for setTitle(TitleRole, QString)
+   *  provided for convenience since enum data types may not be
+   *  exported directly through DBus
+   */
+  Q_SCRIPTABLE void setTitle(int role, const QString& title);
+
+  /** Returns the session's title for the specified @p role.
+   * This is an overloaded member function for  setTitle(TitleRole)
+   * provided for convenience since enum data types may not be
+   * exported directly through DBus
+   */
+  Q_SCRIPTABLE QString title(int role) const;
+
+  /** Returns the "friendly" version of the QUuid of this session.
+  * This is a QUuid with the braces and dashes removed, so it cannot be
+  * used to construct a new QUuid. The same text appears in the
+  * SHELL_SESSION_ID environment variable.
+  */
+  Q_SCRIPTABLE QString shellSessionId() const;
+
+  /** Sets the session's tab title format for the specified @p context to @p format.
+   *  This is an overloaded member function for setTabTitleFormat(TabTitleContext, QString)
+   *  provided for convenience since enum data types may not be
+   *  exported directly through DBus
+   */
+  Q_SCRIPTABLE void setTabTitleFormat(int context, const QString& format);
+
+  /** Returns the session's tab title format for the specified @p context.
+   * This is an overloaded member function for tabTitleFormat(TitleRole)
+   * provided for convenience since enum data types may not be
+   * exported directly through DBus
+   */
+  Q_SCRIPTABLE QString tabTitleFormat(int context) const;
+
+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 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&);
+  /** 
+   * Requests that the text color of views on this session should
+   * be changed to @p color.
+   */
+  void changeForegroundColorRequest(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 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();
+
+  void updateFlowControlState(bool suspended);
+  void updateWindowSize(int lines, int columns);
+private:
+
+  void updateTerminalSize();
+  WId windowId() const;
+  bool kill(int signal);
+  // print a warning message in the terminal.  This is used
+  // if the program fails to start, or if the shell exits in 
+  // an unsuccessful manner
+  void terminalWarning(const QString& message);
+  // checks that the binary 'program' is available and can be executed
+  // returns the binary name if available or an empty string otherwise
+  QString checkProgram(const QString& program) const;
+  ProcessInfo* getProcessInfo();
+  void updateSessionProcessInfo();
+  bool updateForegroundProcessInfo();
+  ProcessInfo* updateWorkingDirectory();
+
+  QUuid            _uniqueIdentifier; // SHELL_SESSION_ID
+
+  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;
+  QString        _currentWorkingDir;
+
+  ProcessInfo*   _sessionProcessInfo;
+  ProcessInfo*   _foregroundProcessInfo;
+  int            _foregroundPid;
+
+  // 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(QObject* parent);
+    /** 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 slots:
+    void sessionFinished();
+    void forwardData(const char* data, int size);
+
+private:
+    QList<Session*> masters() const;
+
+    // maps sessions to their master status
+    QHash<Session*,bool> _sessions;
+
+    int _masterMode;
+};
+
+#endif
+
+/*
+  Local Variables:
+  mode: c++
+  c-file-style: "stroustrup"
+  indent-tabs-mode: nil
+  tab-width: 4
+  End:
+*/
new file mode 100644
--- /dev/null
+++ b/gui//src/ShellCommand.cpp
@@ -0,0 +1,165 @@
+/*
+    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>
+
+// 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//src/ShellCommand.h
@@ -0,0 +1,88 @@
+/*
+    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>
+
+/** 
+ * 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//src/SimpleEditor.cpp
@@ -0,0 +1,288 @@
+/* Copyright (C) 2010 P.L. Lucas
+ *
+ * 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.
+ */
+
+#include "SimpleEditor.h"
+#include <QFile>
+#include <QTextStream>
+#include <QTextBlock>
+#include <QFileInfo>
+#include <QDir>
+
+SimpleEditor::SimpleEditor(QWidget *parent)
+    : QPlainTextEdit(parent),
+      m_syntaxHighlighter(0),
+      m_firstTimeUse(true) {
+
+    m_completerModel = new QStringListModel ();
+    m_completer = new QCompleter(m_completerModel, this);
+    m_completer->setCompletionMode(QCompleter::PopupCompletion);
+    m_completer->setWidget(this);
+    m_autoIndentation = true;
+    m_automaticIndentationStatement = true;
+
+    QFont font;
+    font.setFamily("Courier");
+    font.setPointSize(10);
+    setFont(font);
+
+    connect(m_completer, SIGNAL(activated(const QString &)), this, SLOT(activated(const QString &)));
+    connect(this, SIGNAL(cursorPositionChanged()), this, SLOT(cursorPositionChangedCallBack()));
+    connect(document(), SIGNAL(contentsChange(int, int, int)), this, SLOT(autoComplete(int, int, int)));
+}
+
+void SimpleEditor::loadSyntaxXMLDescription() {
+    QString installPath = QString("../syntax_files")
+        + QDir::separator();
+
+    QFileInfo file(m_currentFileName);
+    QString suffix = file.suffix();
+
+    if(m_commandsCompletionList.isEmpty()) {
+        QString home = QDir::home().path()
+            + QDir::separator()
+            + ".qtoctave"
+            + QDir::separator()
+            + "commands.txt";
+
+        QFile file(home);
+
+        if(file.open(QFile::ReadOnly)) {
+            char buf[1024];
+            while(file.readLine(buf, sizeof(buf)) >= 0) {
+                m_commandsCompletionList.append(QString(buf).trimmed());
+            }
+            file.close();
+        }
+    }
+
+    QFileInfo xml(installPath + suffix + ".xml");
+    if(xml.exists()) {
+        m_syntaxHighlighter = new SyntaxHighlighter(document());
+        m_syntaxHighlighter->load(xml.absoluteFilePath());
+        m_syntaxHighlighter->setDocument(document());
+    }
+}
+
+bool SimpleEditor::load(QString file) {
+    if(file.isEmpty()) {
+        setPlainText("");
+        m_currentFileName = file;
+        return true;
+    }
+
+    FILE *input = fopen(file.toLocal8Bit().data(),"r");
+    if(!input)
+        return false;
+    fclose(input);
+    QFile in(file);
+    if(!in.open(QIODevice::ReadOnly | QIODevice::Text)) {
+        return false;
+    }
+    QByteArray data = in.readAll();
+    setPlainText(QString::fromLocal8Bit(data));
+    m_currentFileName = file;
+    m_firstTimeUse = false;
+
+    loadSyntaxXMLDescription();
+
+    return true;
+}
+
+bool SimpleEditor::save() {
+    QFile::remove(m_currentFileName + "~");
+    QFile::copy(m_currentFileName, m_currentFileName + "~");
+    FILE *out=fopen(m_currentFileName.toLocal8Bit().data(),"w");
+    if(!out)
+        return false;
+    fprintf(out, "%s", toPlainText().toLocal8Bit().data());
+    fclose(out);
+    document()->setModified(false);
+    return true;
+}
+
+void SimpleEditor::keyPressEvent(QKeyEvent * keyEvent) {
+    //In all cases completer popup must been hided.
+    if(keyEvent->key() != Qt::Key_Return && keyEvent->key() != Qt::Key_Enter) {
+        QAbstractItemView *view = m_completer->popup();
+        if(view->isVisible()) view->hide();
+    }
+
+    if(keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter) {
+        QAbstractItemView *view = m_completer->popup();
+        if(view->isVisible()) {
+            QString word = view->currentIndex().data().toString();
+            if(word.isEmpty()) {
+                word = m_completer->currentCompletion();
+            }
+            activated(word);
+            return;
+        } else if(m_autoIndentation) {
+            QTextCursor cursor = textCursor();
+            QString line = cursor.block().text();
+            QString line2 = line;
+            for(int i=0;i<line.length();i++) {
+                if(line[i] != ' ' && line[i] != '\t') {
+                    line.resize(i);
+                    break;
+                }
+            }
+
+            cursor.insertText("\n" + line);
+            if(m_automaticIndentationStatement) {
+                    QRegExp re("^while .*|^if .*|^for .*|^switch .*|^do$|^try|^function .*|^else$|^elseif .*");
+                    if(re.exactMatch(line2.trimmed())) {
+                            cursor.insertText("\t");
+                    }
+            }
+            setTextCursor(cursor);
+        } else {
+            QPlainTextEdit::keyPressEvent(keyEvent);
+        }
+    } else if(keyEvent->key() == Qt::Key_Tab) {
+            QTextCursor cursor=textCursor();
+            int start=cursor.selectionStart();
+            int end=cursor.selectionEnd();
+            if(start == end) {
+                QPlainTextEdit::keyPressEvent(keyEvent);
+                return;
+            }
+            cursor.beginEditBlock();
+            cursor.setPosition(end);
+            end=cursor.blockNumber();
+            cursor.setPosition(start);
+            cursor.movePosition(QTextCursor::StartOfBlock);
+            while(true) {
+                cursor.insertText("\t");
+                if(cursor.blockNumber()>=end) {
+                    break;
+                }
+                cursor.movePosition(QTextCursor::NextBlock);
+            }
+            cursor.endEditBlock();
+    } else if(keyEvent->key()==Qt::Key_Backtab) {
+        QTextCursor cursor=textCursor();
+        int start=cursor.selectionStart();
+        int end=cursor.selectionEnd();
+        if(start==end) {
+            QPlainTextEdit::keyPressEvent(keyEvent);
+            return;
+        }
+        cursor.beginEditBlock();
+        cursor.setPosition(end);
+        end=cursor.blockNumber();
+        cursor.setPosition(start);
+        cursor.movePosition(QTextCursor::StartOfBlock);
+        while(true) {
+            QString line=cursor.block().text();
+            if(line.length()>0 && (line[0]==' ' || line[0] =='\t')) {
+                cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor);
+                cursor.removeSelectedText();
+            }
+            if(cursor.blockNumber()>=end) break;
+            cursor.movePosition(QTextCursor::NextBlock);
+            cursor.movePosition(QTextCursor::StartOfBlock);
+        }
+        cursor.endEditBlock();
+    } else {
+        if(keyEvent->key()==(Qt::Key_B) && Qt::ControlModifier==keyEvent->modifiers()) {
+            autoComplete(0);
+            return;
+        }
+        QPlainTextEdit::keyPressEvent(keyEvent);
+    }
+}
+
+void SimpleEditor::setCharFormat(QTextCharFormat charFormat) {
+    this->m_charFormat=charFormat;
+    QTextCursor cursor=textCursor();
+    cursor.movePosition(QTextCursor::Start);
+    cursor.setCharFormat(charFormat);
+    cursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor);
+    setFont(charFormat.font());
+
+    QFontMetrics fm(charFormat.font());
+    int textWidthInPixels = fm.width("        ");
+    setTabStopWidth(textWidthInPixels);
+}
+
+void SimpleEditor::activated(const QString& text) {
+    QAbstractItemView *view=m_completer->popup();
+    QTextCursor cursor=textCursor();
+    cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::KeepAnchor);
+    cursor.insertText(text);
+    view->hide();
+}
+
+void SimpleEditor::autoComplete(int position, int charsRemoved, int charsAdded) {
+    if(charsAdded==1)
+            autoComplete();
+}
+
+void SimpleEditor::autoComplete(int size) {
+    QTextCursor cursor = textCursor();
+    cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::KeepAnchor);
+    if(cursor.selectedText().endsWith(" ")
+            || cursor.selectedText().trimmed().length() < size) {
+        return;
+    }
+
+    QStringList list=toPlainText().split(QRegExp("\\W+"));
+    list.removeDuplicates();
+    list.removeOne(cursor.selectedText());
+    list.sort();
+    list.append(m_commandsCompletionList);
+
+    m_completerModel->setStringList(list);
+    m_completer->setCompletionPrefix(cursor.selectedText());
+
+    if(m_completer->completionCount() > 0) {
+            QRect r=cursorRect(cursor);
+            r.setWidth(200);
+            m_completer->complete(r);
+    }
+}
+
+QString SimpleEditor::getFileName() {
+    return m_currentFileName;
+}
+
+void SimpleEditor::setFile(QString file) {
+    m_currentFileName = file;
+    loadSyntaxXMLDescription();
+}
+
+void SimpleEditor::cursorPositionChangedCallBack() {
+    if(m_syntaxHighlighter)
+            m_syntaxHighlighter->setFormatPairBrackets(this);
+}
+
+void SimpleEditor::publicBlockBoundingRectList(QVector<qreal> &list, int &firstLine) {
+    qreal pageBottom = height();
+    QPointF offset = contentOffset();
+    QTextBlock block = firstVisibleBlock();
+    firstLine = block.blockNumber() + 1;
+    qreal first_position = blockBoundingGeometry(block).topLeft().y();
+    for(; block.isValid(); block = block.next()) {
+        QRectF position = blockBoundingGeometry(block);
+        qreal y = position.topLeft().y() + offset.y() - first_position;
+        if(y > pageBottom)
+            break;
+        list.append(y);
+    }
+}
+
new file mode 100644
--- /dev/null
+++ b/gui//src/SimpleEditor.h
@@ -0,0 +1,61 @@
+/* Copyright (C) 2010 P.L. Lucas
+ *
+ * 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.
+ */
+
+#ifndef SIMPLEEDITOR_H
+#define SIMPLEEDITOR_H
+
+#include <QPlainTextEdit>
+#include <QCompleter>
+#include <QStringListModel>
+#include "SyntaxHighlighter.h"
+
+class SimpleEditor : public QPlainTextEdit {
+    Q_OBJECT
+public:
+    SimpleEditor(QWidget * parent = 0);
+    bool load(QString file);
+    bool save();
+    QString getFileName();
+    void setFile(QString file);
+    void setCharFormat(QTextCharFormat m_charFormat);
+    void publicBlockBoundingRectList(QVector<qreal>  &list, int &firstLine);
+    void loadSyntaxXMLDescription();
+
+public slots:
+    void activated(const QString& text);
+    void cursorPositionChangedCallBack();
+    void autoComplete(int size = 3);
+    void autoComplete(int position, int charsRemoved, int charsAdded);
+
+protected:
+    virtual void keyPressEvent(QKeyEvent * e);
+
+private:
+    bool m_firstTimeUse;
+    QString m_currentFileName;
+    QTextCharFormat m_charFormat;
+    QCompleter *m_completer;
+    QStringListModel *m_completerModel;
+    SyntaxHighlighter *m_syntaxHighlighter;
+    QStringList m_commandsCompletionList;
+    bool m_autoIndentation;
+    bool m_automaticIndentationStatement;
+};
+
+#endif // SIMPLEEDITOR_H
+
new file mode 100644
--- /dev/null
+++ b/gui//src/SyntaxHighlighter.cpp
@@ -0,0 +1,486 @@
+/* Copyright (C) 2010 P.L. Lucas
+ *
+ * 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.
+ */
+
+
+#include "SyntaxHighlighter.h"
+#include <QXmlStreamReader>
+#include <QStack>
+#include <QFile>
+#include <stdio.h>
+
+SyntaxHighlighter::SyntaxHighlighter(QObject * parent):QSyntaxHighlighter(parent)
+{
+}
+
+
+bool SyntaxHighlighter::load(QString file)
+{
+	QXmlStreamReader xml;
+	QStack <QString> stack;
+	QFile fileDevice(file);
+	if (!fileDevice.open(QFile::ReadOnly | QFile::Text)) {
+	         return false;
+	}
+	
+	xml.setDevice(&fileDevice);
+	
+	QMap <QString,QString> values;
+	
+	QVector<QString> xmlMainItems;
+	xmlMainItems << "item" << "block" << "bracket";
+	
+	int ruleOrder=0;
+	
+	while (!xml.atEnd())
+	{
+		QXmlStreamReader::TokenType tokenType=xml.readNext();
+		switch(tokenType)
+		{
+			case QXmlStreamReader::StartElement:
+				if(xml.name()!="syntax")
+				{
+					if( xmlMainItems.contains(xml.name().toString()) )
+						stack.push(xml.name().toString());
+					else
+						values[xml.name().toString()]=xml.readElementText().trimmed();
+				}
+			break;
+			case QXmlStreamReader::EndElement:
+				if(stack.isEmpty()) break;
+				QString name=stack.top();
+				if(name==xml.name()) stack.pop();
+				if(stack.isEmpty())
+				{
+					QTextCharFormat format;
+					if(values.contains("bold") && values["bold"]=="true") format.setFontWeight(QFont::Bold);
+					if(values.contains("underline") && values["underline"]=="true") format.setFontUnderline(true);
+					if(values.contains("italic") && values["italic"]=="true") format.setFontItalic(true);
+					if(values.contains("foreground")) format.setForeground(QBrush(QColor(values["foreground"])));
+					if(values.contains("background")) format.setBackground(QBrush(QColor(values["background"])));
+					if(name=="item")
+					{
+						HighlightingRule rule;
+						rule.format=format;
+						rule.pattern=QRegExp(values["pattern"]);
+						rule.ruleOrder=ruleOrder++;
+						highlightingRules.append(rule);
+						values.clear();
+					}
+					else if(name=="block" || name=="bracket")
+					{
+						HighlightingBlockRule rule;
+						rule.format=format;
+						rule.startPattern=QRegExp(values["startPattern"]);
+						rule.endPattern=QRegExp(values["endPattern"]);
+						rule.ruleOrder=ruleOrder++;
+						if(name=="block") highlightingBlockRules.append(rule);
+						else highlightingBracketsRules.append(rule); //Bracket rule
+						values.clear();
+					}
+				}
+			break;
+		}
+	}
+	if (xml.hasError())
+	{
+		// do error handling
+		printf("Error %s: %ld:%ld %s\n", file.toLocal8Bit().data(), xml.lineNumber(), xml.columnNumber(), xml.errorString().toLocal8Bit().data() );
+		return false;
+	}
+	
+	return true;
+}
+
+SyntaxHighlighter::Rule1st SyntaxHighlighter::highlight1stRule(const QString & text, int startIndex)
+{
+	Rule1st rule1st;
+	rule1st.startIndex=text.length();
+	rule1st.rule=-1;
+	
+	for(int i=0; i<highlightingRules.size(); i++)
+	{
+		HighlightingRule *rule=&(highlightingRules[i]);
+		
+		QRegExp *expression = &(rule->pattern);
+		int index = rule->lastFound;
+		if(index>-1 && index<startIndex)
+		{
+			rule->lastFound = index = expression->indexIn(text, startIndex);
+		}
+		if ( index>-1 && index<rule1st.startIndex )
+		{
+			rule1st.startIndex=index;
+			rule1st.length=expression->matchedLength();
+			rule1st.rule=i;
+			rule1st.ruleOrder=rule->ruleOrder;
+		}
+		
+		if(index==startIndex) break;
+	}
+	
+	if(rule1st.rule==-1) rule1st.startIndex=-1;
+	
+	return rule1st;
+}
+
+SyntaxHighlighter::Rule1st SyntaxHighlighter::highlight1stBlockRule(const QString & text, int startIndex)
+{
+	Rule1st rule1st;
+	rule1st.startIndex=text.length();
+	rule1st.rule=-1;
+	
+	for(int i=0; i<highlightingBlockRules.size(); i++)
+	{
+		HighlightingBlockRule rule=highlightingBlockRules[i];
+		
+		int index = rule.startPattern.indexIn(text, startIndex);
+		
+		if ( index>-1 && index<rule1st.startIndex )
+		{
+			rule1st.startIndex=index;
+			rule1st.rule=i;
+			rule1st.ruleOrder=rule.ruleOrder;
+		}
+		
+		if(index==startIndex) break;
+	}
+	
+	if(rule1st.rule==-1) rule1st.startIndex=-1;
+	
+	return rule1st;
+}
+
+/**Inserts brackets in position order in blockData->brackets
+ */
+static void insertInOrder(BlockData *blockData, BlockData::Bracket &bracket)
+{
+	if(blockData->brackets.isEmpty()) blockData->brackets.append(bracket);
+	else
+	{
+		int j=0;
+		
+		for(;j<blockData->brackets.size();j++)
+		{
+			if(blockData->brackets[j].pos>bracket.pos)
+			{
+				blockData->brackets.insert(j,bracket);
+				break;
+			}
+		}
+		if(j>=blockData->brackets.size())
+		{
+			blockData->brackets.append(bracket);
+		}
+	}
+}
+
+
+void SyntaxHighlighter::findBrackets(const QString & text, int start, int end, BlockData *blockData)
+{
+	//blockData->brackets.clear();
+	
+	if( end<0 || end>text.length() ) end=text.length();
+	
+	if(start>end) return;
+	
+	for(int i=0; i<highlightingBracketsRules.size(); i++)
+	{
+		HighlightingBlockRule rule=highlightingBracketsRules[i];
+		
+		int startIndex=start;
+		
+		int index = rule.startPattern.indexIn(text, startIndex);
+		
+		while( index>-1 && index<end )
+		{
+			BlockData::Bracket bracket;
+			bracket.pos=index;
+			bracket.type=i;
+			bracket.length=rule.startPattern.matchedLength();
+			bracket.startBracketOk=true;
+			
+			startIndex=index+bracket.length;
+			
+			insertInOrder(blockData, bracket);
+			index = rule.startPattern.indexIn(text, startIndex);
+		}
+		
+		startIndex=start;
+		
+		index = rule.endPattern.indexIn(text, startIndex);
+		
+		
+		
+		while( index>-1 && index<end )
+		{
+			BlockData::Bracket bracket;
+			bracket.pos=index;
+			bracket.type=i;
+			bracket.length=rule.endPattern.matchedLength();
+			bracket.startBracketOk=false;
+			insertInOrder(blockData, bracket);
+			startIndex=index+bracket.length;
+			index = rule.endPattern.indexIn(text, startIndex);
+		}
+	}
+}
+
+
+int SyntaxHighlighter::ruleSetFormat(Rule1st rule1st)
+{
+	HighlightingRule rule=highlightingRules[rule1st.rule];
+	
+	setFormat(rule1st.startIndex, rule1st.length, rule.format);
+	
+	return rule1st.startIndex + rule1st.length;
+}
+
+
+int SyntaxHighlighter::blockRuleSetFormat(const QString & text, Rule1st rule1st)
+{
+	HighlightingBlockRule rule=highlightingBlockRules[rule1st.rule];
+		
+	int endIndex = rule.endPattern.indexIn(text, rule1st.startIndex);
+	int commentLength;
+	if (endIndex == -1)
+	{
+	    setCurrentBlockState(rule1st.rule);
+	    commentLength = text.length() - rule1st.startIndex;
+	    setFormat(rule1st.startIndex, commentLength, rule.format);
+	    return text.length();
+	}
+	else
+	{
+	    commentLength = endIndex - rule1st.startIndex
+	                    + rule.endPattern.matchedLength();
+	    setFormat(rule1st.startIndex, commentLength, rule.format);
+	    
+	    return endIndex+1;
+	}
+}
+
+
+void SyntaxHighlighter::highlightBlock ( const QString & text )
+{
+
+	setCurrentBlockState(-1);
+	
+	int startIndex = 0;
+	
+	//Checks previous block state
+	if (previousBlockState() >= 0)
+	{
+		Rule1st rule1st;
+		rule1st.rule=previousBlockState();
+		rule1st.startIndex=0;
+		
+		startIndex=blockRuleSetFormat(text,rule1st);
+		
+		//TODO: Posible fallo al establecer el estado del bloque
+		
+		if(startIndex==text.length()) return;
+	}
+	
+	//Gets BlockData
+	BlockData *blockData=new BlockData();
+	
+	//Finds first rule to apply. 
+
+	Rule1st rule1st, blockRule1st;
+	
+	//Find initial matches
+	for(int i=0; i<highlightingRules.size(); i++)
+	{
+		HighlightingRule *rule= &(highlightingRules[i]);
+		QRegExp *expression = &(rule->pattern);
+		int index = expression->indexIn(text, startIndex);
+                rule->lastFound = index;
+	}
+
+	rule1st=highlight1stRule( text, startIndex);
+	blockRule1st=highlight1stBlockRule( text, startIndex);
+
+	while(rule1st.rule>=0 || blockRule1st.rule>=0)
+	{
+		if(rule1st.rule>=0 && blockRule1st.rule>=0)
+		{
+			if
+				( 
+					rule1st.startIndex<blockRule1st.startIndex
+					|| 
+					(
+						rule1st.startIndex==blockRule1st.startIndex
+						&&
+						rule1st.ruleOrder<blockRule1st.ruleOrder
+					)
+				)
+			{
+				findBrackets(text, startIndex, rule1st.startIndex, blockData);
+				startIndex=ruleSetFormat(rule1st);
+				rule1st=highlight1stRule( text, startIndex);
+			}
+			else
+			{
+				findBrackets(text, startIndex, blockRule1st.startIndex, blockData);
+				startIndex=blockRuleSetFormat(text,blockRule1st);
+				blockRule1st=highlight1stBlockRule( text, startIndex);
+			}
+		}
+		else if(rule1st.rule>=0)
+		{
+			findBrackets(text, startIndex, rule1st.startIndex, blockData);
+			startIndex=ruleSetFormat(rule1st);
+			rule1st=highlight1stRule( text, startIndex);
+		}
+		else
+		{
+			findBrackets(text, startIndex, blockRule1st.startIndex, blockData);
+			startIndex=blockRuleSetFormat(text,blockRule1st);
+			blockRule1st=highlight1stBlockRule( text, startIndex);
+		}
+	}
+	
+	findBrackets(text,startIndex, -1, blockData);
+	
+	setCurrentBlockUserData(blockData);
+}
+
+/**Search brackets in one QTextBlock.*/
+static BlockData::Bracket *searchBracket(int i, int increment, int &bracketsCount, BlockData *blockData, BlockData::Bracket *bracket1)
+{
+	if(blockData==NULL) return NULL;
+	
+	if(i==-1) i=blockData->brackets.size()-1;
+	
+	for(; i>=0 && i<blockData->brackets.size(); i+=increment)
+	{
+		BlockData::Bracket *bracket=&(blockData->brackets[i]);
+		if(bracket->type==bracket1->type)
+		{
+			if(bracket->startBracketOk!=bracket1->startBracketOk)
+				bracketsCount--;
+			else
+				bracketsCount++;
+			
+			if(bracketsCount==0)
+				return bracket;
+		}
+	}
+	
+	//printf("[searchBracket] bracketsCount=%d\n", bracketsCount);
+	
+	return NULL;
+}
+
+void SyntaxHighlighter::setFormatPairBrackets(QPlainTextEdit *textEdit)
+{
+	QList<QTextEdit::ExtraSelection> selections;
+	
+	textEdit->setExtraSelections(selections);
+	
+	QTextCursor cursor=textEdit->textCursor();
+	QTextBlock block=cursor.block();
+	BlockData *blockData=(BlockData *)block.userData();
+	if(blockData==NULL) return;
+	
+	int pos=cursor.position()-block.position();
+	
+	BlockData::Bracket *bracket1;
+	QTextBlock block_bracket1=block;
+	
+	int i=blockData->brackets.size()-1;
+	for(; i>=0; i--)
+	{
+		BlockData::Bracket *bracket=&(blockData->brackets[i]);
+		if(bracket->pos==pos)
+		{
+			bracket1=bracket;
+			break;
+		}
+	}
+	
+	if(i<0) return;
+	
+	int increment=(bracket1->startBracketOk) ? +1:-1;
+	int bracketsCount=0;
+	//Looks in this block the other bracket
+	BlockData::Bracket *bracket2=NULL;
+	QTextBlock block_bracket2=block;
+	
+	bracket2=searchBracket( i, increment, bracketsCount, blockData, bracket1);
+	
+	{ //Search brackets in other blocks
+		while( bracket2==NULL )
+		{
+			if(increment>0)
+			{
+				block_bracket2=block_bracket2.next();
+				i=0;
+			}
+			else
+			{
+				block_bracket2=block_bracket2.previous();
+				i=-1;
+			}
+			
+			if(!block_bracket2.isValid()) break;
+			
+			blockData=(BlockData *)block_bracket2.userData();
+			/*
+			printf("[Syntax::setFormatPairBrackets] Interno brackets.size=%d\n", blockData->brackets.size());
+			for(int x=0;x<blockData->brackets.size();x++)
+			{
+				BlockData::Bracket *bracket=&(blockData->brackets[x]);
+				printf("[Syntax::setFormatPairBrackets] bracket.pos=%d bracket.type=%d bracket.len=%d bracket.start=%d\n", bracket->pos, bracket->type, bracket->length, (bracket->startBracketOk) );
+			}
+			*/
+			
+			bracket2=searchBracket( i, increment, bracketsCount, blockData, bracket1);
+		}
+		
+		if(bracket2==NULL) return;
+	}
+	
+	pos=cursor.position();
+	
+	QTextEdit::ExtraSelection selection1;
+	
+	cursor.setPosition(pos+bracket1->length, QTextCursor::KeepAnchor);
+	selection1.cursor=cursor;
+	selection1.format=highlightingBracketsRules[bracket1->type].format;
+	
+	pos=bracket2->pos+block_bracket2.position();
+	QTextEdit::ExtraSelection selection2;
+	cursor.setPosition(pos);
+	cursor.setPosition(pos+bracket2->length, QTextCursor::KeepAnchor);
+	selection2.cursor=cursor;
+	selection2.format=highlightingBracketsRules[bracket2->type].format;
+	
+	selections.append(selection1); selections.append(selection2);
+	
+	textEdit->setExtraSelections(selections);
+	
+}
+
+
+
+BlockData::BlockData():QTextBlockUserData()
+{
+}
+
+
new file mode 100644
--- /dev/null
+++ b/gui//src/SyntaxHighlighter.h
@@ -0,0 +1,107 @@
+/* Copyright (C) 2010 P.L. Lucas
+ *
+ * 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.
+ */
+
+#ifndef __SYNTAX_H__
+#define __SYNTAX_H__
+
+#include <QSyntaxHighlighter>
+#include <QTextBlockUserData>
+#include <QVector>
+#include <QPlainTextEdit>
+
+class BlockData:public QTextBlockUserData
+{
+	public:
+	BlockData();
+	
+	struct Bracket
+	{
+		int type;	//Type of bracket
+		int pos;	//Position of bracket
+		int length;	//Number of chars of bracket
+		bool startBracketOk;	//Is it a start or end bracket?
+	};
+	
+	QVector <Bracket> brackets;
+};
+
+class SyntaxHighlighter:public QSyntaxHighlighter
+{
+	Q_OBJECT
+	
+	struct HighlightingRule
+	{
+		QRegExp pattern;
+		QTextCharFormat format;
+		int ruleOrder;
+		int lastFound;
+	};
+	
+	QVector<HighlightingRule> highlightingRules;
+	
+	struct HighlightingBlockRule
+	{
+		QRegExp startPattern, endPattern;
+		QTextCharFormat format;
+		int ruleOrder;
+	};
+	
+	QVector<HighlightingBlockRule> highlightingBlockRules;
+	QVector<HighlightingBlockRule> highlightingBracketsRules;
+	
+	struct Rule1st
+	{
+		int rule;
+		int startIndex;
+		int length;
+		int ruleOrder;
+	};
+	
+	/**1st rule to apply from startIndex.
+	 */
+	Rule1st highlight1stRule(const QString & text, int startIndex);
+	
+	/**1st block rule to apply from startIndex.
+	 */
+	Rule1st highlight1stBlockRule(const QString & text, int startIndex);
+	
+	/** Set format using rule.
+	 */
+	int ruleSetFormat(Rule1st rule);
+	
+	/** Set format using block rule.
+	 */
+	int blockRuleSetFormat(const QString & text, Rule1st rule1st);
+	
+	/** Finds brackets and put them in BlockData.
+	 */
+	void findBrackets(const QString & text, int start, int end, BlockData *blockData);
+	
+	public:
+	
+        SyntaxHighlighter(QObject * parent = 0);
+	bool load(QString file);
+	
+	/**Formats pair of brackets
+	 */
+	void setFormatPairBrackets(QPlainTextEdit *textEdit);
+	
+	protected:
+	void highlightBlock ( const QString & text );
+};
+#endif
new file mode 100644
--- /dev/null
+++ b/gui//src/TerminalCharacterDecoder.cpp
@@ -0,0 +1,247 @@
+/*
+    This file is part of Konsole, an X terminal.
+    
+    Copyright 2006-2008 by Robert Knight <robertknight@gmail.com>
+    
+    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>
+
+// Konsole
+#include "konsole_wcwidth.h"
+
+PlainTextDecoder::PlainTextDecoder()
+ : _output(0)
+ , _includeTrailingWhitespace(true)
+ , _recordLinePositions(false)
+{
+
+}
+void PlainTextDecoder::setTrailingWhitespace(bool enable)
+{
+    _includeTrailingWhitespace = enable;
+}
+bool PlainTextDecoder::trailingWhitespace() const
+{
+    return _includeTrailingWhitespace;
+}
+void PlainTextDecoder::begin(QTextStream* output)
+{
+   _output = output;
+   if (!_linePositions.isEmpty())
+       _linePositions.clear();
+}
+void PlainTextDecoder::end()
+{
+    _output = 0;
+}
+
+void PlainTextDecoder::setRecordLinePositions(bool record)
+{
+    _recordLinePositions = record;
+}
+QList<int> PlainTextDecoder::linePositions() const
+{
+    return _linePositions;
+}
+void PlainTextDecoder::decodeLine(const Character* const characters, int count, LineProperty /*properties*/
+                             )
+{
+    Q_ASSERT( _output );
+
+    if (_recordLinePositions && _output->string())
+    {
+        int pos = _output->string()->count();
+        _linePositions << pos;
+    }
+
+    //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;)
+    {
+        plainText.append( QChar(characters[i].character) );
+        i += qMax(1,konsole_wcwidth(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;
+
+            bool useBold;
+            ColorEntry::FontWeight weight = characters[i].fontWeight(_colorTable);
+            if (weight == ColorEntry::UseCurrentFormat)
+                useBold = _lastRendition & RE_BOLD;
+            else
+                useBold = weight == ColorEntry::Bold;
+            
+            if (useBold)
+                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//src/TerminalCharacterDecoder.h
@@ -0,0 +1,145 @@
+/*
+    This file is part of Konsole, an X terminal.
+    
+    Copyright 2006-2008 by Robert Knight <robertknight@gmail.com>
+    
+    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"
+
+#include <QList>
+
+class QTextStream;
+
+/**
+ * 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 count The number of characters
+     * @param properties Additional properties which affect all characters in the line
+     */
+    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;
+    /** 
+     * Returns of character positions in the output stream
+     * at which new lines where added.  Returns an empty if setTrackLinePositions() is false or if 
+     * the output device is not a string.
+     */
+    QList<int> linePositions() const;
+    /** Enables recording of character positions at which new lines are added.  See linePositions() */
+    void setRecordLinePositions(bool record);
+
+    virtual void begin(QTextStream* output);
+    virtual void end();
+
+    virtual void decodeLine(const Character* const characters,
+                            int count,
+                            LineProperty properties);    
+
+    
+private:
+    QTextStream* _output;
+    bool _includeTrailingWhitespace;
+
+    bool _recordLinePositions;
+    QList<int> _linePositions;
+};
+
+/**
+ * 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//src/TerminalDisplay.cpp
@@ -0,0 +1,2975 @@
+/*
+    This file is part of Konsole, a terminal emulator for KDE.
+    
+    Copyright 2006-2008 by Robert Knight <robertknight@gmail.com>
+    Copyright 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
+    
+    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/QTimer>
+#include <QtGui/QToolTip>
+#include <QtCore/QTextStream>
+
+#include "Filter.h"
+#include "konsole_wcwidth.h"
+#include "ScreenWindow.h"
+#include "TerminalCharacterDecoder.h"
+
+#ifndef loc
+#define loc(X,Y) ((Y)*_columns+(X))
+#endif
+
+#define yMouseScroll 1
+
+#define REPCHAR   "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
+                  "abcdefgjijklmnopqrstuvwxyz" \
+                  "0123456789./+@"
+
+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), ColorEntry( QColor(0xB2,0xB2,0xB2), 1), // Dfore, Dback
+  ColorEntry(QColor(0x00,0x00,0x00), 0), ColorEntry( QColor(0xB2,0x18,0x18), 0), // Black, Red
+  ColorEntry(QColor(0x18,0xB2,0x18), 0), ColorEntry( QColor(0xB2,0x68,0x18), 0), // Green, Yellow
+  ColorEntry(QColor(0x18,0x18,0xB2), 0), ColorEntry( QColor(0xB2,0x18,0xB2), 0), // Blue, Magenta
+  ColorEntry(QColor(0x18,0xB2,0xB2), 0), ColorEntry( QColor(0xB2,0xB2,0xB2), 0), // Cyan, White
+  // intensiv
+  ColorEntry(QColor(0x00,0x00,0x00), 0), ColorEntry( QColor(0xFF,0xFF,0xFF), 1),
+  ColorEntry(QColor(0x68,0x68,0x68), 0), ColorEntry( QColor(0xFF,0x54,0x54), 0),
+  ColorEntry(QColor(0x54,0xFF,0x54), 0), ColorEntry( QColor(0xFF,0xFF,0x54), 0),
+  ColorEntry(QColor(0x54,0x54,0xFF), 0), ColorEntry( QColor(0xFF,0x54,0xFF), 0),
+  ColorEntry(QColor(0x54,0xFF,0xFF), 0), ColorEntry( QColor(0xFF,0xFF,0xFF), 0)
+};
+
+// scroll increment used when dragging selection at top/bottom of window.
+
+// static
+bool TerminalDisplay::_antialiasText = true;
+bool TerminalDisplay::HAVE_TRANSPARENCY = false;
+
+// we use this to force QPainter to display text in LTR mode
+// more information can be found in: http://unicode.org/reports/tr9/ 
+const QChar LTR_OVERRIDE_CHAR( 0x202D );
+
+/* ------------------------------------------------------------------------- */
+/*                                                                           */
+/*                                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 )
+    {
+
+// TODO: Determine if this is an issue.
+//#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::setBackgroundColor(const QColor& color)
+{
+    _colorTable[DEFAULT_BACK_COLOR].color = color;
+    QPalette p = palette();
+      p.setColor( backgroundRole(), color ); 
+      setPalette( p );
+
+      // Avoid propagating the palette change to the scroll bar 
+      _scrollBar->setPalette( QApplication::palette() );  
+
+    update();
+}
+void TerminalDisplay::setForegroundColor(const QColor& color)
+{
+    _colorTable[DEFAULT_FORE_COLOR].color = color;
+
+    update();
+}
+void TerminalDisplay::setColorTable(const ColorEntry table[])
+{
+  for (int i = 0; i < TABLE_COLORS; i++)
+      _colorTable[i] = table[i];
+
+  setBackgroundColor(_colorTable[DEFAULT_BACK_COLOR].color);
+}
+
+/* ------------------------------------------------------------------------- */
+/*                                                                           */
+/*                                   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 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 ( !QFontInfo(font).fixedPitch() )
+  {
+      //kWarning() << "Using an unsupported variable-width font in the terminal.  This may produce display errors.";
+  }
+
+  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)
+,_boldIntense(true)
+,_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)
+,_hasBlinker(false)
+,_cursorBlinking(false)
+,_hasBlinkingCursor(false)
+,_allowBlinkingText(true)
+,_ctrlDrag(true)
+,_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()));
+
+  //KCursor::setAutoHideCursor( this, true );
+  
+  setUsesMouse(true);
+  setColorTable(base_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->setContentsMargins(0, 0, 0, 0);
+
+  setLayout( _gridLayout ); 
+
+  new AutoScrollHandler(this);
+}
+
+TerminalDisplay::~TerminalDisplay()
+{
+  disconnect(_blinkTimer);
+  disconnect(_blinkCursorTimer);
+  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) && _boldIntense )
+        {
+            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;
+    ColorEntry::FontWeight weight = style->fontWeight(_colorTable);    
+    if (weight == ColorEntry::UseCurrentFormat)
+        useBold = ((style->rendition & RE_BOLD) && _boldIntense) || font().bold();
+    else
+        useBold = (weight == ColorEntry::Bold) ? true : false;
+    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);
+    }
+
+    // setup pen
+    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
+    // This was discussed in: http://lists.kde.org/?t=120552223600002&r=1&w=2
+        if (_bidiEnabled)
+            painter.drawText(rect,0,text);
+        else
+            painter.drawText(rect,0,LTR_OVERRIDE_CHAR+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;
+    _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
+void TerminalDisplay::scrollImage(int lines , const QRect& screenWindowRegion)
+{
+    // if the flow control warning is enabled this will interfere with the 
+    // scrolling optimizations and cause artifacts.  the simple solution here
+    // is to just disable the optimization 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) ); 
+
+    // return if there is nothing to do
+    if (    lines == 0 
+         || _image == 0
+         || !region.isValid() 
+         || (region.top() + abs(lines)) >= region.bottom() 
+         || this->_lines <= region.height() ) return;
+
+    // hide terminal size label to prevent it being scrolled
+    if (_resizeWidget && _resizeWidget->isVisible())
+        _resizeWidget->hide();
+
+    // Note:  With Qt 4.4 the left edge of the scrolled area must be at 0
+    // to get the correct (newly exposed) part of the widget repainted.
+    //
+    // The right edge must be before the left edge of the scroll bar to 
+    // avoid triggering a repaint of the entire widget, the distance is 
+    // given by SCROLLBAR_CONTENT_GAP
+    //
+    // Set the QT_FLUSH_PAINT environment variable to '1' before starting the
+    // application to monitor repainting.
+    //
+    int scrollBarWidth = _scrollBar->isHidden() ? 0 : _scrollBar->width();
+    const int SCROLLBAR_CONTENT_GAP = 1;
+    QRect scrollRect;
+    if ( _scrollbarLocation == ScrollBarLeft )
+    {
+        scrollRect.setLeft(scrollBarWidth+SCROLLBAR_CONTENT_GAP);
+        scrollRect.setRight(width());
+    }
+    else
+    {
+        scrollRect.setLeft(0);
+        scrollRect.setRight(width() - scrollBarWidth - SCROLLBAR_CONTENT_GAP);
+    }
+    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
+        scrollRect.setTop(top);
+    }
+    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
+        scrollRect.setTop(top + abs(lines) * _fontHeight); 
+    }
+    scrollRect.setHeight(linesToMove * _fontHeight );
+
+    Q_ASSERT(scrollRect.isValid() && !scrollRect.isEmpty());
+
+    //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 r;
+        if (hotSpot->startLine()==hotSpot->endLine()) {
+            r.setLeft(hotSpot->startColumn());
+            r.setTop(hotSpot->startLine());
+            r.setRight(hotSpot->endColumn());
+            r.setBottom(hotSpot->endLine());
+            region |= imageToWidget(r);;
+        } else {
+            r.setLeft(hotSpot->startColumn());
+            r.setTop(hotSpot->startLine());
+            r.setRight(_columns);
+            r.setBottom(hotSpot->startLine());
+            region |= imageToWidget(r);;
+            for ( int line = hotSpot->startLine()+1 ; line < hotSpot->endLine() ; line++ ) {
+                r.setLeft(0);
+                r.setTop(line);
+                r.setRight(_columns);
+                r.setBottom(line);
+                region |= imageToWidget(r);;
+            }
+            r.setLeft(0);
+            r.setTop(hotSpot->endLine());
+            r.setRight(hotSpot->endColumn());
+            r.setBottom(hotSpot->endLine());
+            region |= imageToWidget(r);;
+        }
+    }
+    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();
+
+  if (!_image) {
+     // Create _image.
+     // The emitted changedContentSizeSignal also leads to getImage being recreated, so do this first.
+     updateImageSize();
+  }
+
+  Character* const newimg = _screenWindow->getImage();
+  int lines = _screenWindow->windowLines();
+  int columns = _screenWindow->windowColumns();
+
+  setScroll( _screenWindow->currentLine() , _screenWindow->lineCount() );
+
+  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( TEXT_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(QString("Size: XXX x XXX"), this);
+        _resizeWidget->setMinimumWidth(_resizeWidget->fontMetrics().width(QString("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 = QString("Size: %1 x %2").arg(_columns).arg(_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(QApplication::cursorFlashTime() / 2);
+  
+  if (!blink && _blinkCursorTimer->isActive()) 
+  {
+    _blinkCursorTimer->stop();
+    if (_cursorBlinking)
+      blinkCursorEvent();
+    else
+      _cursorBlinking = false;
+  }
+}
+
+void TerminalDisplay::setBlinkingTextEnabled(bool blink)
+{
+    _allowBlinkingText = blink;
+
+    if (blink && !_blinkTimer->isActive()) 
+        _blinkTimer->start(TEXT_BLINK_DELAY);
+  
+    if (!blink && _blinkTimer->isActive()) 
+    {
+        _blinkTimer->stop();
+        _blinking = false;
+    }
+}
+
+void TerminalDisplay::focusOutEvent(QFocusEvent*)
+{
+    // trigger a repaint of the cursor so that it is both visible (in case
+    // it was hidden during blinking)
+    // and drawn in a focused out state
+    _cursorBlinking = false;
+    updateCursor();
+
+    _blinkCursorTimer->stop();
+    if (_blinking)
+        blinkEvent();
+
+    _blinkTimer->stop();
+}
+void TerminalDisplay::focusInEvent(QFocusEvent*)
+{
+    if (_hasBlinkingCursor)
+    {
+        _blinkCursorTimer->start();
+    }
+    updateCursor();
+
+    if (_hasBlinker)
+        _blinkTimer->start();
+}
+
+void TerminalDisplay::paintEvent( QPaintEvent* pe )
+{
+  QPainter paint(this);
+
+  foreach (const QRect &rect, (pe->region() & contentsRect()).rects())
+  {
+    drawBackground(paint,rect,palette().background().color(),
+                    true /* use opacity setting */);
+    drawContents(paint, rect);
+  }
+  drawInputMethodPreeditString(paint,preeditRect());
+  paintFilters(paint);
+}
+
+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)
+{
+    // get color of character under mouse and use it to draw
+    // lines for filters
+    QPoint cursorPos = mapFromGlobal(QCursor::pos());
+    int cursorLine;
+    int cursorColumn;
+    int scrollBarWidth = (_scrollbarLocation == ScrollBarLeft) ? _scrollBar->width() : 0;
+
+    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();
+
+        QRegion region;
+        if ( spot->type() == Filter::HotSpot::Link ) {
+            QRect r;
+            if (spot->startLine()==spot->endLine()) {
+                r.setCoords( spot->startColumn()*_fontWidth + 1 + scrollBarWidth, 
+                             spot->startLine()*_fontHeight + 1,
+                             (spot->endColumn()-1)*_fontWidth - 1 + scrollBarWidth, 
+                             (spot->endLine()+1)*_fontHeight - 1 ); 
+                region |= r;
+            } else {
+                r.setCoords( spot->startColumn()*_fontWidth + 1 + scrollBarWidth, 
+                             spot->startLine()*_fontHeight + 1,
+                             (_columns-1)*_fontWidth - 1 + scrollBarWidth, 
+                             (spot->startLine()+1)*_fontHeight - 1 ); 
+                region |= r;
+                for ( int line = spot->startLine()+1 ; line < spot->endLine() ; line++ ) {
+                    r.setCoords( 0*_fontWidth + 1 + scrollBarWidth, 
+                                 line*_fontHeight + 1,
+                                 (_columns-1)*_fontWidth - 1 + scrollBarWidth,
+                                 (line+1)*_fontHeight - 1 ); 
+                    region |= r;
+                }
+                r.setCoords( 0*_fontWidth + 1 + scrollBarWidth,
+                             spot->endLine()*_fontHeight + 1,
+                             (spot->endColumn()-1)*_fontWidth - 1 + scrollBarWidth,
+                             (spot->endLine()+1)*_fontHeight - 1 ); 
+                region |= r;
+            }
+        }
+
+        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 + scrollBarWidth,
+                         line*_fontHeight + 1,
+                         endColumn*_fontWidth - 1 + scrollBarWidth,
+                         (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 ( region.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)
+{
+  QPoint tL  = contentsRect().topLeft();
+  int    tLx = tL.x();
+  int    tLy = tL.y();
+
+  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;
+  QString unistr;
+  unistr.reserve(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;
+
+      // reset our buffer to the maximal size
+      unistr.resize(bufferSize);
+      QChar *disstrU = unistr.data();
+
+      // 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;
+         unistr.resize(p);
+
+         // Create a text scaling matrix for double width and double height lines.
+         QMatrix textScale;
+
+         if (y < _lineProperties.size())
+         {
+            if (_lineProperties[y] & LINE_DOUBLEWIDTH)
+                textScale.scale(2,1);
+
+            if (_lineProperties[y] & LINE_DOUBLEHEIGHT)
+                textScale.scale(1,2);
+         }
+
+         //Apply text scaling matrix.
+         paint.setWorldMatrix(textScale, true);
+
+         //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)    
+         textArea.moveTopLeft( textScale.inverted().map(textArea.topLeft()) );
+         
+         //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.setWorldMatrix(textScale.inverted(), true);
+
+         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;
+    }
+  }
+}
+
+void TerminalDisplay::blinkEvent()
+{
+  if (!_allowBlinkingText) return;
+
+  _blinking = !_blinking;
+
+  //TODO:  Optimize 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
+{
+    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::updateCursor()
+{
+  QRect cursorRect = imageToWidget( QRect(cursorPosition(),QSize(1,1)) ); 
+  update(cursorRect);
+}
+
+void TerminalDisplay::blinkCursorEvent()
+{
+  _cursorBlinking = !_cursorBlinking;
+  updateCursor();
+}
+
+/* ------------------------------------------------------------------------- */
+/*                                                                           */
+/*                                  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()
+{
+  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.
+//
+//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)
+{
+  // 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(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;
+  int scrollBarWidth = (_scrollbarLocation == ScrollBarLeft) ? _scrollBar->width() : 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)
+  {
+    QRegion previousHotspotArea = _mouseOverHotspotArea;
+    _mouseOverHotspotArea = QRegion();
+    QRect r;
+    if (spot->startLine()==spot->endLine()) {
+        r.setCoords( spot->startColumn()*_fontWidth + scrollBarWidth, 
+                     spot->startLine()*_fontHeight,
+                     spot->endColumn()*_fontWidth + scrollBarWidth, 
+                     (spot->endLine()+1)*_fontHeight - 1 ); 
+        _mouseOverHotspotArea |= r;
+    } else {
+        r.setCoords( spot->startColumn()*_fontWidth + scrollBarWidth,
+                     spot->startLine()*_fontHeight,
+                     _columns*_fontWidth - 1 + scrollBarWidth,
+                     (spot->startLine()+1)*_fontHeight ); 
+        _mouseOverHotspotArea |= r;
+        for ( int line = spot->startLine()+1 ; line < spot->endLine() ; line++ ) {
+            r.setCoords( 0*_fontWidth + scrollBarWidth, 
+                         line*_fontHeight,
+                         _columns*_fontWidth + scrollBarWidth,
+                         (line+1)*_fontHeight ); 
+            _mouseOverHotspotArea |= r;
+        }
+        r.setCoords( 0*_fontWidth + scrollBarWidth, 
+                     spot->endLine()*_fontHeight,
+                     spot->endColumn()*_fontWidth + scrollBarWidth, 
+                     (spot->endLine()+1)*_fontHeight ); 
+        _mouseOverHotspotArea |= r;
+    }
+    // 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.boundingRect() );
+    }
+
+    update( _mouseOverHotspotArea | previousHotspotArea );
+  }
+  else if ( !_mouseOverHotspotArea.isEmpty() )
+  {
+        update( _mouseOverHotspotArea );
+        // set hotspot area to an invalid rectangle
+        _mouseOverHotspotArea = QRegion();
+  }
+  
+  // 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() );
+}
+
+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.
+
+  int linesBeyondWidget = 0;
+
+  QRect textBounds(tLx + _leftMargin,
+                     tLy + _topMargin,
+                   _usedColumns*_fontWidth-1,
+                   _usedLines*_fontHeight-1);
+
+  // Adjust position within text area bounds.
+  QPoint oldpos = pos;
+ 
+  pos.setX( qBound(textBounds.left(),pos.x(),textBounds.right()) );
+  pos.setY( qBound(textBounds.top(),pos.y(),textBounds.bottom()) );
+
+  if ( oldpos.y() > textBounds.bottom() ) 
+  {
+      linesBeyondWidget = (oldpos.y()-textBounds.bottom()) / _fontHeight;
+    _scrollBar->setValue(_scrollBar->value()+linesBeyondWidget+1); // scrollforward
+  }
+  if ( oldpos.y() < textBounds.top() )
+  {
+      linesBeyondWidget = (textBounds.top()-oldpos.y()) / _fontHeight;
+    _scrollBar->setValue(_scrollBar->value()-linesBeyondWidget-1); // history
+  }
+
+  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;
+    QChar 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;
+    QChar 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...
+  QChar 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 the terminal program is not interested mouse events
+  // then send the event to the scrollbar if the slider has room to move
+  // or otherwise send simulated up / down key presses to the terminal program
+  // for the benefit of programs such as 'less'
+  if ( _mouseMarks )
+  {
+    bool canScroll = _scrollBar->maximum() > 0;
+      if (canScroll)
+        _scrollBar->event(ev);
+    else
+    {
+        // assume that each Up / Down key event will cause the terminal application
+        // to scroll by one line.  
+        //
+        // to get a reasonable scrolling speed, scroll by one line for every 5 degrees
+        // of mouse wheel rotation.  Mouse wheels typically move in steps of 15 degrees,
+        // giving a scroll of 3 lines
+        int key = ev->delta() > 0 ? Qt::Key_Up : Qt::Key_Down;
+
+        // QWheelEvent::delta() gives rotation in eighths of a degree
+        int wheelDegrees = ev->delta() / 8;
+        int linesToScroll = abs(wheelDegrees) / 5;
+
+        QKeyEvent keyScrollEvent(QEvent::KeyPress,key,Qt::NoModifier);
+
+        for (int i=0;i<linesToScroll;i++)
+            emit keyPressedSignal(&keyScrollEvent);
+    }
+  }
+  else
+  {
+    // terminal program wants notification of mouse activity
+    
+    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());
+    QChar 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 );
+}
+
+
+QChar TerminalDisplay::charClass(QChar qch) const
+{
+    if ( qch.isSpace() ) return ' ';
+
+    if ( qch.isLetterOrNumber() || _wordCharacters.contains(qch, Qt::CaseInsensitive ) )
+    return 'a';
+
+    return qch;
+}
+
+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);
+  if (!text.isEmpty())
+    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 )
+{
+    bool emitKeyPressSignal = true;
+
+    if(event->modifiers() == Qt::ControlModifier)
+    {
+        switch(event->key()) {
+            case Qt::Key_C:
+                copyClipboard();
+                break;
+            case Qt::Key_V:
+                pasteClipboard();
+                break;
+        };
+    } else if ( event->modifiers() == Qt::ShiftModifier ) {
+        bool update = true;
+
+        if ( event->key() == Qt::Key_PageUp )
+        {
+            _screenWindow->scrollBy( ScreenWindow::ScrollPages , -1 );
+        }
+        else if ( event->key() == Qt::Key_PageDown )
+        {
+            _screenWindow->scrollBy( ScreenWindow::ScrollPages , 1 );
+        }
+        else if ( event->key() == Qt::Key_Up )
+        {
+            _screenWindow->scrollBy( ScreenWindow::ScrollLines , -1 );
+        }
+        else if ( event->key() == Qt::Key_Down )
+        {
+            _screenWindow->scrollBy( ScreenWindow::ScrollLines , 1 );
+        }
+        else
+            update = false;
+
+        if ( update )
+        {
+            _screenWindow->setTrackOutput( _screenWindow->atEndOfOutput() );
+            
+            updateLineProperties();
+            updateImage();
+
+            // do not send key press to terminal
+            emitKeyPressSignal = false;
+        }
+    }
+
+    _actSel=0; // Key stroke implies a screen update, so TerminalDisplay won't
+              // know where the current selection is.
+
+    if (_hasBlinkingCursor) 
+    {
+      _blinkCursorTimer->start(QApplication::cursorFlashTime() / 2);
+      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;
+        default:
+            break;
+    }
+
+    return QVariant();
+}
+
+bool TerminalDisplay::handleShortcutOverrideEvent(QKeyEvent* keyEvent)
+{
+    int modifiers = keyEvent->modifiers();
+
+    //  When a possible shortcut combination is pressed, 
+    //  emit the overrideShortcutCheck() signal to allow the host
+    //  to decide whether the terminal should override it or not.
+    if (modifiers != Qt::NoModifier) 
+    {
+        int modifierCount = 0;
+        unsigned int currentModifier = Qt::ShiftModifier;
+
+        while (currentModifier <= Qt::KeypadModifier)
+        {
+            if (modifiers & currentModifier)
+                modifierCount++;
+            currentModifier <<= 1;
+        }
+        if (modifierCount < 2) 
+        {
+            bool override = false;
+            emit overrideShortcutCheck(keyEvent,override);
+            if (override)
+            {
+                keyEvent->accept();
+                return true;
+            }
+        }
+    }
+
+    // Override any of the following shortcuts because
+    // they are needed by the terminal
+    int keyCode = keyEvent->key() | 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 false;
+}
+
+bool TerminalDisplay::event(QEvent* event)
+{
+  bool eventHandled = false;
+  switch (event->type())
+  {
+    case QEvent::ShortcutOverride:
+        eventHandled = handleShortcutOverrideEvent((QKeyEvent*)event);
+        break;
+    case QEvent::PaletteChange:
+    case QEvent::ApplicationPaletteChange:
+        _scrollBar->setPalette( QApplication::palette() );
+        break;
+    default:
+        break;
+  }
+  return eventHandled ? true : QWidget::event(event); 
+}
+
+void TerminalDisplay::setBellMode(int mode)
+{
+  _bellMode=mode;
+}
+
+void TerminalDisplay::enableBell()
+{
+    _allowBell = true;
+}
+
+void TerminalDisplay::bell(const QString& message)
+{
+  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) 
+    {
+      // TODO: This will need added back in at some point
+      //KNotification::beep();
+    } 
+    else if (_bellMode==NotifyBell) 
+    {
+      // TODO: This will need added back in at some point
+      //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(_scrollBar->sizeHint().width(), 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()
+{
+  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, this must be synced with calcGeometry()
+void TerminalDisplay::setSize(int columns, int lines)
+{
+  int scrollBarWidth = _scrollBar->isHidden() ? 0 : _scrollBar->sizeHint().width();
+  int horizontalMargin = 2 * DEFAULT_LEFT_MARGIN;
+  int verticalMargin = 2 * DEFAULT_TOP_MARGIN;
+
+  QSize newSize = QSize( horizontalMargin + scrollBarWidth + (columns * _fontWidth)  ,
+                 verticalMargin + (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( QString("<qt>Output has been "
+                                                "<a href=\"http://en.wikipedia.org/wiki/Flow_control\">suspended</a>"
+                                                " by pressing Ctrl+S."
+                                               "  Press <b>Ctrl+Q</b> to resume.</qt>"),
+                                               this );
+
+            QPalette palette(_outputSuspendedLabel->palette());
+            //KColorScheme::adjustBackground(palette,KColorScheme::NeutralBackground);
+            _outputSuspendedLabel->setPalette(palette);
+            _outputSuspendedLabel->setAutoFillBackground(true);
+            _outputSuspendedLabel->setBackgroundRole(QPalette::Base);
+            _outputSuspendedLabel->setFont(QApplication::font());
+            _outputSuspendedLabel->setContentsMargins(5, 5, 5, 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.
+}
+
+AutoScrollHandler::AutoScrollHandler(QWidget* parent)
+: QObject(parent)
+, _timerId(0)
+{
+    //parent->installEventFilter(this);
+}
+void AutoScrollHandler::timerEvent(QTimerEvent* event)
+{
+    if (event->timerId() != _timerId)
+        return;
+
+    QMouseEvent mouseEvent(    QEvent::MouseMove,
+                              widget()->mapFromGlobal(QCursor::pos()),
+                              Qt::NoButton,
+                              Qt::LeftButton,
+                              Qt::NoModifier);
+
+    QApplication::sendEvent(widget(),&mouseEvent);    
+}
+bool AutoScrollHandler::eventFilter(QObject* watched,QEvent* event)
+{
+    Q_ASSERT( watched == parent() );
+    Q_UNUSED( watched );
+
+    QMouseEvent* mouseEvent = (QMouseEvent*)event;
+    switch (event->type())
+    {
+        case QEvent::MouseMove:
+        {
+            bool mouseInWidget = widget()->rect().contains(mouseEvent->pos());
+
+            if (mouseInWidget)
+            {
+                if (_timerId)
+                    killTimer(_timerId);
+                _timerId = 0;
+            }
+            else
+            {
+                if (!_timerId && (mouseEvent->buttons() & Qt::LeftButton))
+                    _timerId = startTimer(100);
+            }
+                break;
+        }
+        case QEvent::MouseButtonRelease:
+            if (_timerId && (mouseEvent->buttons() & ~Qt::LeftButton))
+            {
+                killTimer(_timerId);
+                _timerId = 0;
+            }
+        break;
+        default:
+        break;
+    };
+
+    return false;
+}
new file mode 100644
--- /dev/null
+++ b/gui//src/TerminalDisplay.h
@@ -0,0 +1,816 @@
+/*
+    Copyright 2007-2008 by Robert Knight <robertknight@gmail.com>
+    Copyright 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
+
+    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"
+
+class QDrag;
+class QDragEnterEvent;
+class QDropEvent;
+class QLabel;
+class QTimer;
+class QEvent;
+class QGridLayout;
+class QKeyEvent;
+class QScrollBar;
+class QShowEvent;
+class QHideEvent;
+class QTimerEvent;
+class QWidget;
+
+class KMenu;
+
+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);
+
+    /** Specifies whether or not text can blink. */
+    void setBlinkingTextEnabled(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;   }
+
+    /**
+     * Specifies whether characters with intense colors should be rendered
+     * as bold. Defaults to true.
+     */
+    void setBoldIntense(bool value) { _boldIntense = value; }
+    /**
+     * Returns true if characters with intense colors are rendered in bold.
+     */
+    bool getBoldIntense() { return _boldIntense; }
+    
+    /**
+     * 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; }
+
+    /**
+     * Sets the status of the BiDi rendering inside the terminal display.
+     * Defaults to disabled.
+     */
+    void setBidiEnabled(bool set) { _bidiEnabled=set; }
+    /**
+     * Returns the status of the BiDi rendering in this widget.
+     */
+    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);
+    /** 
+     * Returns true if the flow control warning box is enabled. 
+     * See outputSuspended() and setFlowControlWarningEnabled()
+     */
+    bool flowControlWarningEnabled() const
+    { return _flowControlWarningEnabled; }
+
+    /** 
+     * 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);
+
+    /** 
+     * Sets the background of the display to the specified color. 
+     * @see setColorTable(), setForegroundColor() 
+     */
+    void setBackgroundColor(const QColor& color);
+
+    /** 
+     * Sets the text of the display to the specified color. 
+     * @see setColorTable(), setBackgroundColor()
+     */
+    void setForegroundColor(const QColor& color);
+
+signals:
+
+    /**
+     * Emitted when the user presses a key whilst the terminal widget has focus.
+     */
+    void keyPressedSignal(QKeyEvent *e);
+
+    /** 
+     * 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(const QPoint& position);
+
+    /**
+     * When a shortcut which is also a valid terminal key sequence is pressed while 
+     * the terminal widget  has focus, this signal is emitted to allow the host to decide 
+     * whether the shortcut should be overridden.  
+     * When the shortcut is overridden, the key sequence will be sent to the terminal emulation instead
+     * and the action associated with the shortcut will not be triggered.
+     *
+     * @p override is set to false by default and the shortcut will be triggered as normal.
+     */
+    void overrideShortcutCheck(QKeyEvent* keyEvent,bool& override);
+
+   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 focusInEvent(QFocusEvent* event);
+    virtual void focusOutEvent(QFocusEvent* event);
+    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;
+
+    // classifies the 'ch' into one of three categories
+    // and returns a character to indicate which category it is in
+    //
+    //     - A space (returns ' ') 
+    //     - Part of a word (returns 'a')
+    //     - Other characters (returns the input character)
+    QChar charClass(QChar ch) 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;
+
+    // redraws the cursor
+    void updateCursor();
+
+    bool handleShortcutOverrideEvent(QKeyEvent* event);
+
+    // 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
+    bool _boldIntense;   // Whether intense colors should be rendered with bold font
+
+    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 _allowBlinkingText;  // allow text to blink
+    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;
+    QRegion _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 TEXT_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;
+    }
+};
+
+class AutoScrollHandler : public QObject
+{
+Q_OBJECT
+
+public:
+    AutoScrollHandler(QWidget* parent);
+protected:
+    virtual void timerEvent(QTimerEvent* event);
+    virtual bool eventFilter(QObject* watched,QEvent* event);
+private:
+    QWidget* widget() const { return static_cast<QWidget*>(parent()); }
+    int _timerId;
+};
+
+
+#endif // TERMINALDISPLAY_H
new file mode 100644
--- /dev/null
+++ b/gui//src/VariablesDockWidget.cpp
@@ -0,0 +1,168 @@
+#include "VariablesDockWidget.h"
+#include <QHBoxLayout>
+#include <QVBoxLayout>
+#include <QPushButton>
+
+VariablesDockWidget::VariablesDockWidget(QWidget *parent)
+    : QDockWidget(parent) {
+    setObjectName("VariablesDockWidget");
+    construct();
+}
+
+void VariablesDockWidget::construct() {
+    m_updateSemaphore = new QSemaphore(1);
+    QStringList headerLabels;
+    headerLabels << tr("Name") << tr("Type") << tr("Value");
+    m_variablesTreeWidget = new QTreeWidget(this);
+    m_variablesTreeWidget->setHeaderHidden(false);
+    m_variablesTreeWidget->setHeaderLabels(headerLabels);
+    QVBoxLayout *layout = new QVBoxLayout();
+
+    setWindowTitle(tr("Workspace"));
+    setWidget(new QWidget());
+
+    layout->addWidget(m_variablesTreeWidget);
+    QWidget *buttonBar = new QWidget(this);
+    layout->addWidget(buttonBar);
+
+        QHBoxLayout *buttonBarLayout = new QHBoxLayout();
+        QPushButton *saveWorkspaceButton = new QPushButton(tr("Save"), buttonBar);
+        QPushButton *loadWorkspaceButton = new QPushButton(tr("Load"), buttonBar);
+        QPushButton *clearWorkspaceButton = new QPushButton(tr("Clear"), buttonBar);
+        buttonBarLayout->addWidget(saveWorkspaceButton);
+        buttonBarLayout->addWidget(loadWorkspaceButton);
+        buttonBarLayout->addWidget(clearWorkspaceButton);
+        buttonBarLayout->setMargin(2);
+        buttonBar->setLayout(buttonBarLayout);
+
+    layout->setMargin(2);
+    widget()->setLayout(layout);
+
+    connect(saveWorkspaceButton, SIGNAL(clicked()), this, SLOT(emitSaveWorkspace()));
+    connect(loadWorkspaceButton, SIGNAL(clicked()), this, SLOT(emitLoadWorkspace()));
+    connect(clearWorkspaceButton, SIGNAL(clicked()), this, SLOT(emitClearWorkspace()));
+
+    QTreeWidgetItem *treeWidgetItem = new QTreeWidgetItem();
+    treeWidgetItem->setData(0, 0, QString(tr("Local")));
+    m_variablesTreeWidget->insertTopLevelItem(0, treeWidgetItem);
+
+    treeWidgetItem = new QTreeWidgetItem();
+    treeWidgetItem->setData(0, 0, QString(tr("Global")));
+    m_variablesTreeWidget->insertTopLevelItem(1, treeWidgetItem);
+
+    treeWidgetItem = new QTreeWidgetItem();
+    treeWidgetItem->setData(0, 0, QString(tr("Persistent")));
+    m_variablesTreeWidget->insertTopLevelItem(2, treeWidgetItem);
+
+    treeWidgetItem = new QTreeWidgetItem();
+    treeWidgetItem->setData(0, 0, QString(tr("Hidden")));
+    m_variablesTreeWidget->insertTopLevelItem(3, treeWidgetItem);
+
+    m_variablesTreeWidget->expandAll();
+    m_variablesTreeWidget->setAlternatingRowColors(true);
+    m_variablesTreeWidget->setAnimated(true);    
+}
+
+void VariablesDockWidget::updateTreeEntry(QTreeWidgetItem *treeItem, SymbolRecord symbolRecord) {
+    treeItem->setData(0, 0, QString(symbolRecord.name().c_str()));
+    treeItem->setData(1, 0, QString(symbolRecord.varval().type_name().c_str()));
+    treeItem->setData(2, 0, OctaveLink::octaveValueAsQString(symbolRecord.varval()));
+}
+
+void VariablesDockWidget::setVariablesList(QList<SymbolRecord> symbolTable) {
+    m_updateSemaphore->acquire();
+    // Split the symbol table into its different scopes.
+    QList<SymbolRecord> localSymbolTable;
+    QList<SymbolRecord> globalSymbolTable;
+    QList<SymbolRecord> persistentSymbolTable;
+    QList<SymbolRecord> hiddenSymbolTable;
+
+    foreach(SymbolRecord symbolRecord, symbolTable) {
+        // It's true that being global or hidden includes it's can mean it's also locally visible,
+        // but we want to distinguish that here.
+        if(symbolRecord.is_local() && !symbolRecord.is_global() && !symbolRecord.is_hidden()) {
+            localSymbolTable.append(symbolRecord);
+        }
+
+        if(symbolRecord.is_global()) {
+            globalSymbolTable.append(symbolRecord);
+        }
+
+        if(symbolRecord.is_persistent()) {
+            persistentSymbolTable.append(symbolRecord);
+        }
+
+        if(symbolRecord.is_hidden()) {
+            hiddenSymbolTable.append(symbolRecord);
+        }
+    }
+
+    updateScope(0, localSymbolTable);
+    updateScope(1, globalSymbolTable);
+    updateScope(2, persistentSymbolTable);
+    updateScope(3, hiddenSymbolTable);
+    m_updateSemaphore->release();
+}
+
+void VariablesDockWidget::updateScope(int topLevelItemIndex, QList<SymbolRecord> symbolTable) {
+    // This method may be a little bit confusing; variablesList is a complete list of all
+    // variables that are in the workspace currently.
+    QTreeWidgetItem *topLevelItem = m_variablesTreeWidget->topLevelItem(topLevelItemIndex);
+
+    // First we check, if any variables that exist in the model tree have to be updated
+    // or created. So we walk the variablesList check against the tree.
+    foreach(SymbolRecord symbolRecord, symbolTable) {
+        int childCount = topLevelItem->childCount();
+        bool alreadyExists = false;
+        QTreeWidgetItem *child;
+
+        // Search for the corresponding item in the tree. If it has been found, child
+        // will contain the appropriate QTreeWidgetItem* pointing at it.
+        for(int i = 0; i < childCount; i++) {
+            child = topLevelItem->child(i);
+            if(child->data(0, 0).toString() == QString(symbolRecord.name().c_str())) {
+                alreadyExists = true;
+                break;
+            }
+        }
+
+        // If it already exists, just update it.
+        if(alreadyExists) {
+            updateTreeEntry(child, symbolRecord);
+        } else {
+            // It does not exist, so create a new one and set the right values.
+            child = new QTreeWidgetItem();
+            updateTreeEntry(child, symbolRecord);
+            topLevelItem->addChild(child);
+        }
+    }
+
+    // Check the tree against the list for deleted variables.
+    for(int i = 0; i < topLevelItem->childCount(); i++) {
+        bool existsInVariableList = false;
+        QTreeWidgetItem *child = topLevelItem->child(i);
+        foreach(SymbolRecord symbolRecord, symbolTable) {
+            if(QString(symbolRecord.name().c_str()) == child->data(0, 0).toString()) {
+                existsInVariableList = true;
+            }
+        }
+
+        if(!existsInVariableList) {
+            topLevelItem->removeChild(child);
+            delete child;
+            i--;
+        }
+    }
+}
+
+void VariablesDockWidget::emitSaveWorkspace() {
+    emit saveWorkspace();
+}
+
+void VariablesDockWidget::emitLoadWorkspace() {
+    emit loadWorkspace();
+}
+
+void VariablesDockWidget::emitClearWorkspace() {
+    emit clearWorkspace();
+}
new file mode 100644
--- /dev/null
+++ b/gui//src/VariablesDockWidget.h
@@ -0,0 +1,34 @@
+#ifndef VARIABLESDOCKWIDGET_H
+#define VARIABLESDOCKWIDGET_H
+
+#include <QDockWidget>
+#include <QTreeWidget>
+#include <QSemaphore>
+#include "OctaveLink.h"
+
+class VariablesDockWidget : public QDockWidget
+{
+    Q_OBJECT
+public:
+    VariablesDockWidget(QWidget *parent = 0);
+    void setVariablesList(QList<SymbolRecord> symbolTable);
+
+signals:
+    void saveWorkspace();
+    void loadWorkspace();
+    void clearWorkspace();
+
+private slots:
+    void emitSaveWorkspace();
+    void emitLoadWorkspace();
+    void emitClearWorkspace();
+
+private:
+    void construct();
+    void updateTreeEntry(QTreeWidgetItem *treeItem, SymbolRecord symbolRecord);
+    void updateScope(int topLevelItemIndex, QList<SymbolRecord> symbolTable);
+    QTreeWidget *m_variablesTreeWidget;
+    QSemaphore *m_updateSemaphore;
+};
+
+#endif // VARIABLESDOCKWIDGET_H
new file mode 100644
--- /dev/null
+++ b/gui//src/Vt102Emulation.cpp
@@ -0,0 +1,1214 @@
+/*
+    This file is part of Konsole, an X terminal.
+    
+    Copyright 2007-2008 by Robert Knight <robert.knight@gmail.com>
+    Copyright 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
+
+    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"
+
+
+// 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
+
+#if defined(HAVE_XKB)
+    void scrolllock_set_off();
+    void scrolllock_set_on();
+#endif
+
+// Standard 
+#include <stdio.h>
+#include <unistd.h>
+#include <assert.h>
+
+// Qt
+#include <QtCore/QEvent>
+#include <QtGui/QKeyEvent>
+#include <QtCore/QByteRef>
+
+// Konsole
+#include "KeyboardTranslator.h"
+#include "Screen.h"
+
+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()
+{
+  resetTokenizer();
+  resetModes();
+  resetCharset(0);
+  _screen[0]->reset();
+  resetCharset(1);
+  _screen[1]->reset();
+  setCodec(LocaleCodec);
+ 
+  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 (processToken)
+
+   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 window/terminal attribute commands 
+                  of the form <ESC>`]' {Pn} `;' {Text} <BEL>
+                  (Note that these are handled differently to the other formats)
+
+   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_CONSTRUCT(T,A,N) ( ((((int)N) & 0xffff) << 16) | ((((int)A) & 0xff) << 8) | (((int)T) & 0xff) )
+
+#define TY_CHR(   )     TY_CONSTRUCT(0,0,0)
+#define TY_CTL(A  )     TY_CONSTRUCT(1,A,0)
+#define TY_ESC(A  )     TY_CONSTRUCT(2,A,0)
+#define TY_ESC_CS(A,B)  TY_CONSTRUCT(3,A,B)
+#define TY_ESC_DE(A  )  TY_CONSTRUCT(4,A,0)
+#define TY_CSI_PS(A,N)  TY_CONSTRUCT(5,A,N)
+#define TY_CSI_PN(A  )  TY_CONSTRUCT(6,A,0)
+#define TY_CSI_PR(A,N)  TY_CONSTRUCT(7,A,N)
+
+#define TY_VT52(A)    TY_CONSTRUCT(8,A,0)
+#define TY_CSI_PG(A)  TY_CONSTRUCT(9,A,0)
+#define TY_CSI_PE(A)  TY_CONSTRUCT(10,A,0)
+
+#define MAX_ARGUMENT 4096
+
+// Tokenizer --------------------------------------------------------------- --
+
+/* The tokenizer's state
+
+   The state is represented by the buffer (tokenBuffer, tokenBufferPos),
+   and accompanied by decoded arguments kept in (argv,argc).
+   Note that they are kept internal in the tokenizer.
+*/
+
+void Vt102Emulation::resetTokenizer()
+{
+  tokenBufferPos = 0; 
+  argc = 0; 
+  argv[0] = 0; 
+  argv[1] = 0;
+}
+
+void Vt102Emulation::addDigit(int digit)
+{
+  if (argv[argc] < MAX_ARGUMENT)
+      argv[argc] = 10*argv[argc] + digit;
+}
+
+void Vt102Emulation::addArgument()
+{
+  argc = qMin(argc+1,MAXARGS-1);
+  argv[argc] = 0;
+}
+
+void Vt102Emulation::addToCurrentToken(int cc)
+{
+  tokenBuffer[tokenBufferPos] = cc;
+  tokenBufferPos = qMin(tokenBufferPos+1,MAX_TOKEN_LENGTH-1);
+}
+
+// Character Class flags used while decoding
+
+#define CTL  1  // Control character
+#define CHR  2  // Printable character
+#define CPN  4  // TODO: Document me 
+#define DIG  8  // Digit
+#define SCS 16  // TODO: Document me  
+#define GRP 32  // TODO: Document me
+#define CPS 64  // Character which indicates end of window resize
+                // escape sequence '\e[8;<row>;<col>t'
+
+void Vt102Emulation::initTokenizer()
+{ 
+  int i; 
+  quint8* s;
+  for(i = 0;i < 256; ++i) 
+    charClass[i] = 0;
+  for(i = 0;i < 32; ++i) 
+    charClass[i] |= CTL;
+  for(i = 32;i < 256; ++i) 
+    charClass[i] |= CHR;
+  for(s = (quint8*)"@ABCDGHILMPSTXZcdfry"; *s; ++s) 
+    charClass[*s] |= CPN;
+  // resize = \e[8;<row>;<col>t
+  for(s = (quint8*)"t"; *s; ++s) 
+    charClass[*s] |= CPS;
+  for(s = (quint8*)"0123456789"; *s; ++s) 
+    charClass[*s] |= DIG;
+  for(s = (quint8*)"()+*%"; *s; ++s) 
+    charClass[*s] |= SCS;
+  for(s = (quint8*)"()+*#[]%"; *s; ++s) 
+    charClass[*s] |= GRP;
+
+  resetTokenizer();
+}
+
+/* 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 'charClass').
+   
+   - 'cc' is the current character
+   - 's' is a pointer to the start of the token buffer
+   - 'p' is the current position within the token buffer 
+
+   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 && (charClass[s[(L)]] & (C)) == (C))
+#define eec(C)     (p >=  3  && cc == (C))
+#define ees(C)     (p >=  3  && cc < 256 && (charClass[cc] & (C)) == (C))
+#define eps(C)     (p >=  3  && s[2] != '?' && s[2] != '!' && s[2] != '>' && cc < 256 && (charClass[cc] & (C)) == (C))
+#define epp( )     (p >=  3  && s[2] == '?')
+#define epe( )     (p >=  3  && s[2] == '!')
+#define egt( )     (p >=  3  && s[2] == '>')
+#define Xpe        (tokenBufferPos >= 2 && tokenBuffer[1] == ']')
+#define Xte        (Xpe      && cc ==  7 )
+#define ces(C)     (cc < 256 && (charClass[cc] & (C)) == (C) && !Xte)
+
+#define ESC 27
+#define CNTL(c) ((c)-'@')
+
+// process an incoming unicode character
+void Vt102Emulation::receiveChar(int cc)
+{ 
+  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 resetTokenizer() 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) 
+        resetTokenizer(); //VT100: CAN or SUB
+    if (cc != ESC)    
+    { 
+        processToken(TY_CTL(cc+'@' ),0,0); 
+        return; 
+    }
+  }
+  // advance the state
+  addToCurrentToken(cc); 
+
+  int* s = tokenBuffer;
+  int  p = tokenBufferPos;
+
+  if (getMode(MODE_Ansi)) 
+  {
+    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         ) { processWindowAttributeChange(); resetTokenizer(); return; }
+    if (Xpe         ) { return; }
+    if (lec(3,2,'?')) { return; }
+    if (lec(3,2,'>')) { return; }
+    if (lec(3,2,'!')) { return; }
+    if (lun(       )) { processToken( TY_CHR(), applyCharset(cc), 0);   resetTokenizer(); return; }
+    if (lec(2,0,ESC)) { processToken( TY_ESC(s[1]), 0, 0);              resetTokenizer(); return; }
+    if (les(3,1,SCS)) { processToken( TY_ESC_CS(s[1],s[2]), 0, 0);      resetTokenizer(); return; }
+    if (lec(3,1,'#')) { processToken( TY_ESC_DE(s[2]), 0, 0);           resetTokenizer(); return; }
+    if (eps(    CPN)) { processToken( TY_CSI_PN(cc), argv[0],argv[1]);  resetTokenizer(); return; }
+
+    // resize = \e[8;<row>;<col>t
+    if (eps(CPS)) 
+    { 
+        processToken( TY_CSI_PS(cc, argv[0]), argv[1], argv[2]);   
+        resetTokenizer(); 
+        return; 
+    }
+
+    if (epe(   )) { processToken( TY_CSI_PE(cc), 0, 0); resetTokenizer(); return; }
+    if (ees(DIG)) { addDigit(cc-'0'); return; }
+    if (eec(';')) { addArgument();    return; }
+    for (int i=0;i<=argc;i++)
+    {
+        if (epp())  
+            processToken( TY_CSI_PR(cc,argv[i]), 0, 0);
+        else if (egt())   
+            processToken( 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;
+            processToken( 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;
+            processToken( TY_CSI_PS(cc, argv[i-2]), COLOR_SPACE_256, argv[i]);
+        }
+        else
+            processToken( TY_CSI_PS(cc,argv[i]), 0, 0);
+    }
+    resetTokenizer();
+  }
+  else 
+  {
+    // VT52 Mode
+    if (lec(1,0,ESC))                                                      
+        return;
+    if (les(1,0,CHR)) 
+    { 
+        processToken( TY_CHR(), s[0], 0); 
+        resetTokenizer(); 
+        return; 
+    }
+    if (lec(2,1,'Y'))                                                      
+        return;
+    if (lec(3,1,'Y'))                                                      
+        return;
+    if (p < 4) 
+    { 
+        processToken( TY_VT52(s[1] ), 0, 0); 
+        resetTokenizer(); 
+        return; 
+    }
+    processToken( TY_VT52(s[1]), s[2], s[3]); 
+    resetTokenizer(); 
+    return;
+  }
+}
+void Vt102Emulation::processWindowAttributeChange()
+{
+  // Describes the window or terminal session attribute to change
+  // See Session::UserTitleChange for possible values
+  int attributeToChange = 0;
+  int i;
+  for (i = 2; i < tokenBufferPos     && 
+              tokenBuffer[i] >= '0'  && 
+              tokenBuffer[i] <= '9'; i++)
+  {
+    attributeToChange = 10 * attributeToChange + (tokenBuffer[i]-'0');
+  }
+
+  if (tokenBuffer[i] != ';') 
+  { 
+    reportDecodingError(); 
+    return; 
+  }
+  
+  QString newValue;
+  newValue.reserve(tokenBufferPos-i-2);
+  for (int j = 0; j < tokenBufferPos-i-2; j++)
+    newValue[j] = tokenBuffer[i+1+j];
+ 
+  _pendingTitleUpdates[attributeToChange] = newValue;
+  _titleUpdateTimer->start(20);
+}
+
+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::processToken(int token, int p, int q)
+{
+  switch (token)
+  {
+
+    case TY_CHR(         ) : _currentScreen->displayCharacter     (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->tab                  (          ); 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->toStartOfLine        (          ); 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->displayCharacter     (    0x2592); break; //VT100
+    case TY_CTL('Y'      ) : /* EM : ignored                      */ break;
+    case TY_CTL('Z'      ) : _currentScreen->displayCharacter     (    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 /* columns */, 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('J',      3) : clearHistory();                            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->tab                  (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->backtab              (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) :          setMode      (MODE_132Columns);break; //VT100
+    case TY_CSI_PR('l',   3) :        resetMode      (MODE_132Columns);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',  40) :         setMode(MODE_Allow132Columns ); break; // XTERM
+    case TY_CSI_PR('l',  40) :       resetMode(MODE_Allow132Columns ); break; // XTERM
+
+    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', 1034) : /* IGNORED: 8bitinput activation     */ 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: 
+        reportDecodingError();    
+        break;
+  };
+}
+
+void Vt102Emulation::clearScreenAndSetColumns(int columnCount)
+{
+    setImageSize(_currentScreen->getLines(),columnCount); 
+    clearEntireScreen();
+    setDefaultMargins(); 
+    _currentScreen->setCursorYX(0,0);
+}
+
+void Vt102Emulation::sendString(const char* s , int length)
+{
+  if ( length >= 0 )
+    emit sendData(s,length);
+  else
+    emit sendData(s,strlen(s));
+}
+
+void Vt102Emulation::reportCursorPosition()
+{ 
+  char tmp[20];
+  sprintf(tmp,"\033[%d;%dR",_currentScreen->getCursorY()+1,_currentScreen->getCursorX()+1);
+  sendString(tmp);
+}
+
+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.
+}
+
+void Vt102Emulation::reportAnswerBack()
+{
+  // FIXME - Test this with VTTEST
+  // This is really obsolete VT100 stuff.
+  const char* ANSWER_BACK = "";
+  sendString(ANSWER_BACK);
+}
+
+/*!
+    `cx',`cy' are 1-based.
+    `eventType' 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 )
+{ 
+  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
+
+  char command[20];
+  sprintf(command,"\033[M%c%c%c",cb+0x20,cx+0x20,cy+0x20);
+  sendString(command);
+}
+
+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;
+    if (getMode(MODE_AppKeyPad) && (modifiers & Qt::KeypadModifier)) 
+        states |= KeyboardTranslator::ApplicationKeypadState;
+
+    // check flow control state
+    if (modifiers & Qt::ControlModifier)
+    {
+        if (event->key() == Qt::Key_S)
+            emit flowControlKeyPressed(true);
+        else if (event->key() == Qt::Key_Q)
+            emit flowControlKeyPressed(false);
+    }
+
+    // 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 += eraseChar();
+
+            // 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 =  QString("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);
+}
+
+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();
+}
+
+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()
+{
+  // MODE_Allow132Columns is not reset here
+  // to match Xterm's behaviour (see Xterm's VTReset() function)
+
+  resetMode(MODE_132Columns); saveMode(MODE_132Columns);
+  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);
+  resetMode(MODE_AppCuKeys);  saveMode(MODE_AppCuKeys);
+  resetMode(MODE_AppKeyPad);  saveMode(MODE_AppKeyPad);
+  resetMode(MODE_NewLine);
+  setMode(MODE_Ansi);
+}
+
+void Vt102Emulation::setMode(int m)
+{
+  _currentModes.mode[m] = true;
+  switch (m)
+  {
+    case MODE_132Columns:
+        if (getMode(MODE_Allow132Columns))
+            clearScreenAndSetColumns(132);
+        else
+            _currentModes.mode[m] = false;
+        break;
+    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)
+{
+  _currentModes.mode[m] = false;
+  switch (m)
+  {
+    case MODE_132Columns:
+        if (getMode(MODE_Allow132Columns))
+            clearScreenAndSetColumns(80);
+        break;
+    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)
+{
+  _savedModes.mode[m] = _currentModes.mode[m];
+}
+
+void Vt102Emulation::restoreMode(int m)
+{
+  if (_savedModes.mode[m]) 
+      setMode(m); 
+  else 
+      resetMode(m);
+}
+
+bool Vt102Emulation::getMode(int m)
+{
+  return _currentModes.mode[m];
+}
+
+char Vt102Emulation::eraseChar() const
+{
+  KeyboardTranslator::Entry entry = _keyTranslator->findEntry(
+                                            Qt::Key_Backspace,
+                                            0,
+                                            0);
+  if ( entry.text().count() > 0 )
+      return entry.text()[0];
+  else
+      return '\b';
+}
+
+// print contents of the scan buffer
+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::reportDecodingError()
+{
+  if (tokenBufferPos == 0 || ( tokenBufferPos == 1 && (tokenBuffer[0] & 0xff) >= 32) ) 
+    return;
+  printf("Undecodable sequence: "); 
+  hexdump(tokenBuffer,tokenBufferPos); 
+  printf("\n");
+}
+
new file mode 100644
--- /dev/null
+++ b/gui//src/Vt102Emulation.h
@@ -0,0 +1,186 @@
+/*
+    This file is part of Konsole, an X terminal.
+    
+    Copyright 2007-2008 by Robert Knight <robertknight@gmail.com>
+    Copyright 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
+
+    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)   // Mode #1
+#define MODE_AppCuKeys       (MODES_SCREEN+1)   // Application cursor keys (DECCKM)
+#define MODE_AppKeyPad       (MODES_SCREEN+2)   // 
+#define MODE_Mouse1000       (MODES_SCREEN+3)   // Send mouse X,Y position on press and release
+#define MODE_Mouse1001       (MODES_SCREEN+4)   // Use Hilight mouse tracking
+#define MODE_Mouse1002       (MODES_SCREEN+5)   // Use cell motion mouse tracking
+#define MODE_Mouse1003       (MODES_SCREEN+6)   // Use all motion mouse tracking 
+#define MODE_Ansi            (MODES_SCREEN+7)   // Use US Ascii for character sets G0-G3 (DECANM) 
+#define MODE_132Columns      (MODES_SCREEN+8)   // 80 <-> 132 column mode switch (DECCOLM)
+#define MODE_Allow132Columns (MODES_SCREEN+9)   // Allow DECCOLM mode
+#define MODE_total           (MODES_SCREEN+10)
+
+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 from Emulation
+  virtual void clearEntireScreen();
+  virtual void reset();
+  virtual char eraseChar() const;
+  
+public slots: 
+  // reimplemented from Emulation 
+  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 from Emulation
+  virtual void setMode(int mode);
+  virtual void resetMode(int mode);
+  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
+  // (except MODE_Allow132Columns)
+  void resetModes();
+
+  void resetTokenizer();
+  #define MAX_TOKEN_LENGTH 80
+  void addToCurrentToken(int cc);
+  int tokenBuffer[MAX_TOKEN_LENGTH]; //FIXME: overflow?
+  int tokenBufferPos;
+#define MAXARGS 15
+  void addDigit(int dig);
+  void addArgument();
+  int argv[MAXARGS];
+  int argc;
+  void initTokenizer();
+
+  // Set of flags for each of the ASCII characters which indicates
+  // what category they fall into (printable character, control, digit etc.)
+  // for the purposes of decoding terminal output
+  int charClass[256];
+
+  void reportDecodingError(); 
+
+  void processToken(int code, int p, int q);
+  void processWindowAttributeChange();
+
+  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];
+
+  class TerminalState
+  {
+  public:
+    // Initializes all modes to false
+    TerminalState()
+    { memset(&mode,false,MODE_total * sizeof(bool)); }
+
+    bool mode[MODE_total];
+  };
+
+  TerminalState _currentModes;
+  TerminalState _savedModes;
+
+  //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//src/konsole_export.h
@@ -0,0 +1,67 @@
+/*
+    This file is part of the KDE project
+    Copyright (C) 2009 Patrick Spendrin <ps_ml@gmx.de>
+
+    This library 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 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 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 KONSOLE_EXPORT_H
+#define KONSOLE_EXPORT_H
+
+/* needed for KDE_EXPORT macros */
+//#include <kdemacros.h>
+#include <QtCore/qglobal.h>
+#define KDE_EXPORT
+#define KDE_IMPORT
+
+#ifndef KONSOLEPRIVATE_EXPORT
+# if defined(MAKE_KONSOLEPRIVATE_LIB)
+   /* We are building this library */
+#  define KONSOLEPRIVATE_EXPORT KDE_EXPORT
+# else
+   /* We are using this library */
+#  define KONSOLEPRIVATE_EXPORT KDE_IMPORT
+# endif
+#endif
+
+#include <iostream>
+//#define kWarning(x) std::cout
+
+#include <stdio.h>
+
+//#define i18n 
+inline QString i18n(char *buff,...)
+{
+  char msg[2048];
+    va_list arglist;
+
+    va_start(arglist,buff);
+
+    snprintf(msg,2048,buff, arglist);
+
+    va_end(arglist);
+
+    return QString(msg);
+}
+
+#define i18nc 
+
+
+//#define KDE_fseek ::fseek
+//#define KDE_lseek ::lseek
+
+
+#endif
new file mode 100644
--- /dev/null
+++ b/gui//src/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//src/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//src/kprocess.cpp
@@ -0,0 +1,345 @@
+/*
+    This file is part of the KDE libraries
+
+    Copyright (C) 2007 Oswald Buddenhagen <ossi@kde.org>
+
+    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 "kprocess_p.h"
+
+#include <qfile.h>
+
+#ifdef Q_OS_WIN
+# include <windows.h>
+#else
+# include <unistd.h>
+# include <errno.h>
+#endif
+
+#ifndef Q_OS_WIN
+# define STD_OUTPUT_HANDLE 1
+# define STD_ERROR_HANDLE 2
+#endif
+
+#ifdef _WIN32_WCE
+#include <stdio.h>
+#endif
+
+void KProcessPrivate::writeAll(const QByteArray &buf, int fd)
+{
+#ifdef Q_OS_WIN
+#ifndef _WIN32_WCE
+    HANDLE h = GetStdHandle(fd);
+    if (h) {
+        DWORD wr;
+        WriteFile(h, buf.data(), buf.size(), &wr, 0);
+    }
+#else
+    fwrite(buf.data(), 1, buf.size(), (FILE*)fd);
+#endif
+#else
+    int off = 0;
+    do {
+        int ret = ::write(fd, buf.data() + off, buf.size() - off);
+        if (ret < 0) {
+            if (errno != EINTR)
+                return;
+        } else {
+            off += ret;
+        }
+    } while (off < buf.size());
+#endif
+}
+
+void KProcessPrivate::forwardStd(KProcess::ProcessChannel good, int fd)
+{
+    Q_Q(KProcess);
+
+    QProcess::ProcessChannel oc = q->readChannel();
+    q->setReadChannel(good);
+    writeAll(q->readAll(), fd);
+    q->setReadChannel(oc);
+}
+
+void KProcessPrivate::_k_forwardStdout()
+{
+#ifndef _WIN32_WCE
+    forwardStd(KProcess::StandardOutput, STD_OUTPUT_HANDLE);
+#else
+    forwardStd(KProcess::StandardOutput, (int)stdout);
+#endif
+}
+
+void KProcessPrivate::_k_forwardStderr()
+{
+#ifndef _WIN32_WCE
+    forwardStd(KProcess::StandardError, STD_ERROR_HANDLE);
+#else
+    forwardStd(KProcess::StandardError, (int)stderr);
+#endif
+}
+
+/////////////////////////////
+// public member functions //
+/////////////////////////////
+
+KProcess::KProcess(QObject *parent) :
+    QProcess(parent),
+    d_ptr(new KProcessPrivate)
+{
+    d_ptr->q_ptr = this;
+    setOutputChannelMode(ForwardedChannels);
+}
+
+KProcess::KProcess(KProcessPrivate *d, QObject *parent) :
+    QProcess(parent),
+    d_ptr(d)
+{
+    d_ptr->q_ptr = this;
+    setOutputChannelMode(ForwardedChannels);
+}
+
+KProcess::~KProcess()
+{
+    delete d_ptr;
+}
+
+void KProcess::setOutputChannelMode(OutputChannelMode mode)
+{
+    Q_D(KProcess);
+
+    d->outputChannelMode = mode;
+    disconnect(this, SIGNAL(readyReadStandardOutput()));
+    disconnect(this, SIGNAL(readyReadStandardError()));
+    switch (mode) {
+    case OnlyStdoutChannel:
+        connect(this, SIGNAL(readyReadStandardError()), SLOT(_k_forwardStderr()));
+        break;
+    case OnlyStderrChannel:
+        connect(this, SIGNAL(readyReadStandardOutput()), SLOT(_k_forwardStdout()));
+        break;
+    default:
+        QProcess::setProcessChannelMode((ProcessChannelMode)mode);
+        return;
+    }
+    QProcess::setProcessChannelMode(QProcess::SeparateChannels);
+}
+
+KProcess::OutputChannelMode KProcess::outputChannelMode() const
+{
+    Q_D(const KProcess);
+
+    return d->outputChannelMode;
+}
+
+void KProcess::setNextOpenMode(QIODevice::OpenMode mode)
+{
+    Q_D(KProcess);
+
+    d->openMode = mode;
+}
+
+#define DUMMYENV "_KPROCESS_DUMMY_="
+
+void KProcess::clearEnvironment()
+{
+    setEnvironment(QStringList() << QString::fromLatin1(DUMMYENV));
+}
+
+void KProcess::setEnv(const QString &name, const QString &value, bool overwrite)
+{
+    QStringList env = environment();
+    if (env.isEmpty()) {
+        env = systemEnvironment();
+        env.removeAll(QString::fromLatin1(DUMMYENV));
+    }
+    QString fname(name);
+    fname.append(QLatin1Char('='));
+    for (QStringList::Iterator it = env.begin(); it != env.end(); ++it)
+        if ((*it).startsWith(fname)) {
+            if (overwrite) {
+                *it = fname.append(value);
+                setEnvironment(env);
+            }
+            return;
+        }
+    env.append(fname.append(value));
+    setEnvironment(env);
+}
+
+void KProcess::unsetEnv(const QString &name)
+{
+    QStringList env = environment();
+    if (env.isEmpty()) {
+        env = systemEnvironment();
+        env.removeAll(QString::fromLatin1(DUMMYENV));
+    }
+    QString fname(name);
+    fname.append(QLatin1Char('='));
+    for (QStringList::Iterator it = env.begin(); it != env.end(); ++it)
+        if ((*it).startsWith(fname)) {
+            env.erase(it);
+            if (env.isEmpty())
+                env.append(QString::fromLatin1(DUMMYENV));
+            setEnvironment(env);
+            return;
+        }
+}
+
+void KProcess::setProgram(const QString &exe, const QStringList &args)
+{
+    Q_D(KProcess);
+
+    d->prog = exe;
+    d->args = args;
+#ifdef Q_OS_WIN
+    setNativeArguments(QString());
+#endif
+}
+
+void KProcess::setProgram(const QStringList &argv)
+{
+    Q_D(KProcess);
+
+    Q_ASSERT( !argv.isEmpty() );
+    d->args = argv;
+    d->prog = d->args.takeFirst();
+#ifdef Q_OS_WIN
+    setNativeArguments(QString());
+#endif
+}
+
+KProcess &KProcess::operator<<(const QString &arg)
+{
+    Q_D(KProcess);
+
+    if (d->prog.isEmpty())
+        d->prog = arg;
+    else
+        d->args << arg;
+    return *this;
+}
+
+KProcess &KProcess::operator<<(const QStringList &args)
+{
+    Q_D(KProcess);
+
+    if (d->prog.isEmpty())
+        setProgram(args);
+    else
+        d->args << args;
+    return *this;
+}
+
+void KProcess::clearProgram()
+{
+    Q_D(KProcess);
+
+    d->prog.clear();
+    d->args.clear();
+#ifdef Q_OS_WIN
+    setNativeArguments(QString());
+#endif
+}
+
+void KProcess::setShellCommand(const QString &cmd)
+{
+    Q_D(KProcess);
+    d->args.clear();
+    d->prog = QString::fromLatin1("/bin/sh");
+    d->args << QString::fromLatin1("-c") << cmd;
+}
+
+QStringList KProcess::program() const
+{
+    Q_D(const KProcess);
+
+    QStringList argv = d->args;
+    argv.prepend(d->prog);
+    return argv;
+}
+
+void KProcess::start()
+{
+    Q_D(KProcess);
+
+    QProcess::start(d->prog, d->args, d->openMode);
+}
+
+int KProcess::execute(int msecs)
+{
+    start();
+    if (!waitForFinished(msecs)) {
+        kill();
+        waitForFinished(-1);
+        return -2;
+    }
+    return (exitStatus() == QProcess::NormalExit) ? exitCode() : -1;
+}
+
+// static
+int KProcess::execute(const QString &exe, const QStringList &args, int msecs)
+{
+    KProcess p;
+    p.setProgram(exe, args);
+    return p.execute(msecs);
+}
+
+// static
+int KProcess::execute(const QStringList &argv, int msecs)
+{
+    KProcess p;
+    p.setProgram(argv);
+    return p.execute(msecs);
+}
+
+int KProcess::startDetached()
+{
+    Q_D(KProcess);
+
+    qint64 pid;
+    if (!QProcess::startDetached(d->prog, d->args, workingDirectory(), &pid))
+        return 0;
+    return (int) pid;
+}
+
+// static
+int KProcess::startDetached(const QString &exe, const QStringList &args)
+{
+    qint64 pid;
+    if (!QProcess::startDetached(exe, args, QString(), &pid))
+        return 0;
+    return (int) pid;
+}
+
+// static
+int KProcess::startDetached(const QStringList &argv)
+{
+    QStringList args = argv;
+    QString prog = args.takeFirst();
+    return startDetached(prog, args);
+}
+
+int KProcess::pid() const
+{
+#ifdef Q_OS_UNIX
+    return (int) QProcess::pid();
+#else
+    return QProcess::pid() ? QProcess::pid()->dwProcessId : 0;
+#endif
+}
+
new file mode 100644
--- /dev/null
+++ b/gui//src/kprocess.h
@@ -0,0 +1,342 @@
+/*
+    This file is part of the KDE libraries
+
+    Copyright (C) 2007 Oswald Buddenhagen <ossi@kde.org>
+
+    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 KPROCESS_H
+#define KPROCESS_H
+
+#include <QtCore/QProcess>
+class KProcess;
+class KProcessPrivate;
+
+
+/**
+ * \class KProcess kprocess.h <KProcess>
+ * 
+ * Child process invocation, monitoring and control.
+ *
+ * This class extends QProcess by some useful functionality, overrides
+ * some defaults with saner values and wraps parts of the API into a more
+ * accessible one.
+ * This is the preferred way of spawning child processes in KDE; don't
+ * use QProcess directly.
+ *
+ * @author Oswald Buddenhagen <ossi@kde.org>
+ **/
+class KProcess : public QProcess
+{
+    Q_OBJECT
+    Q_DECLARE_PRIVATE(KProcess)
+
+public:
+
+    /**
+     * Modes in which the output channels can be opened.
+     */
+    enum OutputChannelMode {
+        SeparateChannels = QProcess::SeparateChannels,
+            /**< Standard output and standard error are handled by KProcess
+                 as separate channels */
+        MergedChannels = QProcess::MergedChannels,
+            /**< Standard output and standard error are handled by KProcess
+                 as one channel */
+        ForwardedChannels = QProcess::ForwardedChannels,
+            /**< Both standard output and standard error are forwarded
+                 to the parent process' respective channel */
+        OnlyStdoutChannel,
+            /**< Only standard output is handled; standard error is forwarded */
+        OnlyStderrChannel  /**< Only standard error is handled; standard output is forwarded */
+    };
+
+    /**
+     * Constructor
+     */
+    explicit KProcess(QObject *parent = 0);
+
+    /**
+     * Destructor
+     */
+    virtual ~KProcess();
+
+    /**
+     * Set how to handle the output channels of the child process.
+     *
+     * The default is ForwardedChannels, which is unlike in QProcess.
+     * Do not request more than you actually handle, as this output is
+     * simply lost otherwise.
+     *
+     * This function must be called before starting the process.
+     *
+     * @param mode the output channel handling mode
+     */
+    void setOutputChannelMode(OutputChannelMode mode);
+
+    /**
+     * Query how the output channels of the child process are handled.
+     *
+     * @return the output channel handling mode
+     */
+    OutputChannelMode outputChannelMode() const;
+
+    /**
+     * Set the QIODevice open mode the process will be opened in.
+     *
+     * This function must be called before starting the process, obviously.
+     *
+     * @param mode the open mode. Note that this mode is automatically
+     *   "reduced" according to the channel modes and redirections.
+     *   The default is QIODevice::ReadWrite.
+     */
+    void setNextOpenMode(QIODevice::OpenMode mode);
+
+    /**
+     * 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
+     * @param overwrite if @c false and the environment variable is already
+     *   set, the old value will be preserved
+     */
+    void setEnv(const QString &name, const QString &value, bool overwrite = true);
+
+    /**
+     * Removes the variable @p name from the process' environment.
+     *
+     * This function must be called before starting the process.
+     *
+     * @param name the name of the environment variable
+     */
+    void unsetEnv(const QString &name);
+
+    /**
+     * Empties the process' environment.
+     *
+     * Note that LD_LIBRARY_PATH/DYLD_LIBRARY_PATH is automatically added
+     * on *NIX.
+     *
+     * This function must be called before starting the process.
+     */
+    void clearEnvironment();
+
+    /**
+     * Set the program and the command line arguments.
+     *
+     * This function must be called before starting the process, obviously.
+     *
+     * @param exe the program to execute
+     * @param args the command line arguments for the program,
+     *   one per list element
+     */
+    void setProgram(const QString &exe, const QStringList &args = QStringList());
+
+    /**
+     * @overload
+     *
+     * @param argv the program to execute and the command line arguments
+     *   for the program, one per list element
+     */
+    void setProgram(const QStringList &argv);
+
+    /**
+     * Append an element to the command line argument list for this process.
+     *
+     * If no executable is set yet, it will be set instead.
+     *
+     * For example, doing an "ls -l /usr/local/bin" can be achieved by:
+     *  \code
+     *  KProcess p;
+     *  p << "ls" << "-l" << "/usr/local/bin";
+     *  ...
+     *  \endcode
+     *
+     * This function must be called before starting the process, obviously.
+     *
+     * @param arg the argument to add
+     * @return a reference to this KProcess
+     */
+    KProcess &operator<<(const QString& arg);
+
+    /**
+     * @overload
+     *
+     * @param args the arguments to add
+     * @return a reference to this KProcess
+     */
+    KProcess &operator<<(const QStringList& args);
+
+    /**
+     * Clear the program and command line argument list.
+     */
+    void clearProgram();
+
+    /**
+     * Set a command to execute through a shell (a POSIX sh on *NIX
+     * and cmd.exe on Windows).
+     *
+     * Using this for anything but user-supplied commands is usually a bad
+     * idea, as the command's syntax depends on the platform.
+     * Redirections including pipes, etc. are better handled by the
+     * respective functions provided by QProcess.
+     *
+     * If KProcess determines that the command does not really need a
+     * shell, it will trasparently execute it without one for performance
+     * reasons.
+     *
+     * This function must be called before starting the process, obviously.
+     *
+     * @param cmd the command to execute through a shell.
+     *   The caller must make sure that all filenames etc. are properly
+     *   quoted when passed as argument. Failure to do so often results in
+     *   serious security holes. See KShell::quoteArg().
+     */
+    void setShellCommand(const QString &cmd);
+
+    /**
+     * Obtain the currently set program and arguments.
+     *
+     * @return a list, the first element being the program, the remaining ones
+     *  being command line arguments to the program.
+     */
+    QStringList program() const;
+
+    /**
+     * Start the process.
+     *
+     * @see QProcess::start(const QString &, const QStringList &, OpenMode)
+     */
+    void start();
+
+    /**
+     * Start the process, wait for it to finish, and return the exit code.
+     *
+     * This method is roughly equivalent to the sequence:
+     * <code>
+     *   start();
+     *   waitForFinished(msecs);
+     *   return exitCode();
+     * </code>
+     *
+     * Unlike the other execute() variants this method is not static,
+     * so the process can be parametrized properly and talked to.
+     *
+     * @param msecs time to wait for process to exit before killing it
+     * @return -2 if the process could not be started, -1 if it crashed,
+     *  otherwise its exit code
+     */
+    int execute(int msecs = -1);
+
+    /**
+     * @overload
+     *
+     * @param exe the program to execute
+     * @param args the command line arguments for the program,
+     *   one per list element
+     * @param msecs time to wait for process to exit before killing it
+     * @return -2 if the process could not be started, -1 if it crashed,
+     *  otherwise its exit code
+     */
+    static int execute(const QString &exe, const QStringList &args = QStringList(), int msecs = -1);
+
+    /**
+     * @overload
+     *
+     * @param argv the program to execute and the command line arguments
+     *   for the program, one per list element
+     * @param msecs time to wait for process to exit before killing it
+     * @return -2 if the process could not be started, -1 if it crashed,
+     *  otherwise its exit code
+     */
+    static int execute(const QStringList &argv, int msecs = -1);
+
+    /**
+     * Start the process and detach from it. See QProcess::startDetached()
+     * for details.
+     *
+     * Unlike the other startDetached() variants this method is not static,
+     * so the process can be parametrized properly.
+     * @note Currently, only the setProgram()/setShellCommand() and
+     * setWorkingDirectory() parametrizations are supported.
+     *
+     * The KProcess object may be re-used immediately after calling this
+     * function.
+     *
+     * @return the PID of the started process or 0 on error
+     */
+    int startDetached();
+
+    /**
+     * @overload
+     *
+     * @param exe the program to start
+     * @param args the command line arguments for the program,
+     *   one per list element
+     * @return the PID of the started process or 0 on error
+     */
+    static int startDetached(const QString &exe, const QStringList &args = QStringList());
+
+    /**
+     * @overload
+     *
+     * @param argv the program to start and the command line arguments
+     *   for the program, one per list element
+     * @return the PID of the started process or 0 on error
+     */
+    static int startDetached(const QStringList &argv);
+
+    /**
+     * Obtain the process' ID as known to the system.
+     *
+     * Unlike with QProcess::pid(), this is a real PID also on Windows.
+     *
+     * This function can be called only while the process is running.
+     * It cannot be applied to detached processes.
+     *
+     * @return the process ID
+     */
+    int pid() const;
+
+protected:
+    /**
+     * @internal
+     */
+    KProcess(KProcessPrivate *d, QObject *parent);
+
+    /**
+     * @internal
+     */
+    KProcessPrivate * const d_ptr;
+
+private:
+    // hide those
+    using QProcess::setReadChannelMode;
+    using QProcess::readChannelMode;
+    using QProcess::setProcessChannelMode;
+    using QProcess::processChannelMode;
+
+    Q_PRIVATE_SLOT(d_func(), void _k_forwardStdout())
+    Q_PRIVATE_SLOT(d_func(), void _k_forwardStderr())
+};
+
+#include "kprocess_p.h"
+
+#endif
+
new file mode 100644
--- /dev/null
+++ b/gui//src/kprocess_p.h
@@ -0,0 +1,49 @@
+/*
+    This file is part of the KDE libraries
+
+    Copyright (C) 2007 Oswald Buddenhagen <ossi@kde.org>
+
+    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 KPROCESS_P_H
+#define KPROCESS_P_H
+class KProcess;
+class KProcessPrivate;
+
+#include "kprocess.h"
+class KProcessPrivate {
+    Q_DECLARE_PUBLIC(KProcess)
+protected:
+    KProcessPrivate() :
+        openMode(QIODevice::ReadWrite)
+    {
+    }
+    void writeAll(const QByteArray &buf, int fd);
+    void forwardStd(KProcess::ProcessChannel good, int fd);
+    void _k_forwardStdout();
+    void _k_forwardStderr();
+
+    QString prog;
+    QStringList args;
+    KProcess::OutputChannelMode outputChannelMode;
+    QIODevice::OpenMode openMode;
+
+    KProcess *q_ptr;
+};
+
+
+#endif
new file mode 100644
--- /dev/null
+++ b/gui//src/kpty.cpp
@@ -0,0 +1,710 @@
+/*
+
+   This file is part of the KDE libraries
+   Copyright (C) 2002 Waldo Bastian <bastian@kde.org>
+   Copyright (C) 2002-2003,2007-2008 Oswald Buddenhagen <ossi@kde.org>
+   Copyright (C) 2010 KDE e.V. <kde-ev-board@kde.org>
+     Author Adriaan de Groot <groot@kde.org>
+
+   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
+
+#define HAVE_UTMPX
+#define _UTMPX_COMPAT
+
+#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__) || defined(__sun)
+#  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__) || defined(__sun)
+#  define _tcsetattr(fd, ttmode) tcsetattr(fd, TCSANOW, ttmode)
+# else
+#  define _tcsetattr(fd, ttmode) ioctl(fd, TCSETS, (char *)ttmode)
+# endif
+#endif
+
+#include <QtCore/Q_PID>
+
+#define TTY_GROUP "tty"
+
+#ifndef PATH_MAX
+# ifdef MAXPATHLEN
+#  define PATH_MAX MAXPATHLEN
+# else
+#  define PATH_MAX 1024
+# endif
+#endif
+
+///////////////////////
+// private functions //
+///////////////////////
+
+//////////////////
+// private data //
+//////////////////
+
+KPtyPrivate::KPtyPrivate(KPty* parent) :
+    masterFd(-1), slaveFd(-1), ownMaster(true), q_ptr(parent)
+{
+}
+
+KPtyPrivate::~KPtyPrivate()
+{
+}
+
+#ifndef HAVE_OPENPTY
+bool KPtyPrivate::chownpty(bool grant)
+{
+    return !QProcess::execute(KStandardDirs::findExe("kgrantpty"),
+        QStringList() << (grant?"--grant":"--revoke") << QString::number(masterFd));
+}
+#endif
+
+/////////////////////////////
+// public member functions //
+/////////////////////////////
+
+KPty::KPty() :
+    d_ptr(new KPtyPrivate(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;
+
+  d->ownMaster = 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 = KDE_open(PTM_DEVICE, O_RDWR|O_NOCTTY);
+d->masterFd = ::open(PTM_DEVICE, O_RDWR|O_NOCTTY);
+#else
+# error No method to open a PTY master detected.
+#endif
+  if (d->masterFd >= 0)
+  {
+#ifdef HAVE_PTSNAME
+    char *ptsn = ptsname(d->masterFd);
+    if (ptsn) {
+        d->ttyName = ptsn;
+#else
+    int ptyno;
+    if (!ioctl(d->masterFd, TIOCGPTN, &ptyno)) {
+        char buf[32];
+        sprintf(buf, "/dev/pts/%d", ptyno);
+        d->ttyName = buf;
+#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;
+      }
+    }
+  }
+
+  //kWarning(175) << "Can't open a pseudo teletype";
+  return false;
+
+ gotpty:
+  KDE_struct_stat st;
+  if (KDE_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))
+  {
+
+    /*kWarning(175)
+      << "chownpty failed for device " << ptyName << "::" << d->ttyName
+      << "\nThis means the communication can be eavesdropped." << endl;
+*/  
+}
+
+ grantedpt:
+
+#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)
+  {
+    //kWarning(175) << "Can't open slave pseudo teletype";
+    ::close(d->masterFd);
+    d->masterFd = -1;
+    return false;
+  }
+
+#if (defined(__svr4__) || defined(__sgi__) || defined(Q_OS_SOLARIS))
+  // Solaris uses STREAMS for terminal handling. It is possible
+  // for the pty handling modules to be left off the stream; in that
+  // case push them on. ioctl(fd, I_FIND, ...) is documented to return
+  // 1 if the module is on the stream already.
+  {
+    static const char *pt = "ptem";
+    static const char *ld = "ldterm";
+    if (ioctl(d->slaveFd, I_FIND, pt) == 0)
+      ioctl(d->slaveFd, I_PUSH, pt);
+    if (ioctl(d->slaveFd, I_FIND, ld) == 0)
+      ioctl(d->slaveFd, I_PUSH, ld);
+  }
+#endif
+
+#endif /* HAVE_OPENPTY */
+
+  fcntl(d->masterFd, F_SETFD, FD_CLOEXEC);
+  fcntl(d->slaveFd, F_SETFD, FD_CLOEXEC);
+
+  return true;
+}
+
+bool KPty::open(int fd)
+{
+#if !defined(HAVE_PTSNAME) && !defined(TIOCGPTN)
+    //kWarning(175) << "Unsupported attempt to open pty with fd" << fd;
+    return false;
+#else
+    Q_D(KPty);
+
+    if (d->masterFd >= 0) {
+        //kWarning(175) << "Attempting to open an already open pty";
+        return false;
+    }
+
+    d->ownMaster = false;
+
+# ifdef HAVE_PTSNAME
+    char *ptsn = ptsname(fd);
+    if (ptsn) {
+        d->ttyName = ptsn;
+# else
+    int ptyno;
+    if (!ioctl(fd, TIOCGPTN, &ptyno)) {
+        char buf[32];
+        sprintf(buf, "/dev/pts/%d", ptyno);
+        d->ttyName = buf;
+# endif
+    } else {
+        //kWarning(175) << "Failed to determine pty slave device for fd" << fd;
+        return false;
+    }
+
+    d->masterFd = fd;
+    if (!openSlave()) {
+        d->masterFd = -1;
+        return false;
+    }
+
+    return true;
+#endif
+}
+
+void KPty::closeSlave()
+{
+    Q_D(KPty);
+
+    if (d->slaveFd < 0)
+        return;
+    ::close(d->slaveFd);
+    d->slaveFd = -1;
+}
+
+bool KPty::openSlave()
+{
+    Q_D(KPty);
+
+    if (d->slaveFd >= 0)
+        return true;
+    if (d->masterFd < 0) {
+        //kWarning(175) << "Attempting to open pty slave while master is closed";
+        return false;
+    }
+    d->slaveFd = ::open(d->ttyName.data(), O_RDWR | O_NOCTTY);
+    if (d->slaveFd < 0) {
+        //kWarning(175) << "Can't open slave pseudo teletype";
+        return false;
+    }
+    fcntl(d->slaveFd, F_SETFD, FD_CLOEXEC);
+    return true;
+}
+
+void KPty::close()
+{
+    Q_D(KPty);
+
+    if (d->masterFd < 0)
+        return;
+    closeSlave();
+    if (d->ownMaster) {
+#ifndef HAVE_OPENPTY
+        // 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);
+            }
+        }
+#endif
+        ::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);
+    gettimeofday((struct timeval *)&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);
+	gettimeofday((struct timeval *)&(ut->ut_tv), 0);
+        pututxline(ut);
+    }
+    endutxent();
+#  else
+        ut->ut_time = time(0);
+        pututline(ut);
+    }
+    endutent();
+#  endif
+# endif
+#endif
+}
+
+bool KPty::tcGetAttr(struct ::termios *ttmode) const
+{
+    Q_D(const KPty);
+
+#ifdef Q_OS_SOLARIS
+    if (_tcgetattr(d->slaveFd, ttmode) == 0) return true;
+#endif
+    return _tcgetattr(d->masterFd, ttmode) == 0;
+}
+
+bool KPty::tcSetAttr(struct ::termios *ttmode)
+{
+    Q_D(KPty);
+
+#ifdef Q_OS_SOLARIS
+    if (_tcsetattr(d->slaveFd, ttmode) == 0) return true;
+#endif
+    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//src/kpty.h
@@ -0,0 +1,204 @@
+/* This file is part of the KDE libraries
+
+    Copyright (C) 2003,2007 Oswald Buddenhagen <ossi@kde.org>
+
+    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/qglobal.h>
+
+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();
+
+  /**
+   * Open using an existing pty master.
+   *
+   * @param fd an open pty master file descriptor.
+   *   The ownership of the fd remains with the caller;
+   *   it will not be automatically closed at any point.
+   * @return true if a pty pair was successfully opened
+   */
+  bool open(int fd);
+
+  /**
+   * 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();
+
+  /**
+   * Open the pty slave descriptor.
+   *
+   * This undoes the effect of closeSlave().
+   *
+   * @return true if the pty slave was successfully opened
+   */
+  bool openSlave();
+
+  /**
+   * 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//src/kpty_export.h
@@ -0,0 +1,46 @@
+/*  This file is part of the KDE project
+    Copyright (C) 2007 David Faure <faure@kde.org>
+
+    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_EXPORT_H
+#define KPTY_EXPORT_H
+
+/* needed for KDE_EXPORT and KDE_IMPORT macros */
+//#include <kdemacros.h>
+#include <QtCore/qglobal.h>
+#define KDE_EXPORT
+#define KDE_IMPORT
+
+#ifndef KPTY_EXPORT
+# if defined(KDELIBS_STATIC_LIBS)
+   /* No export/import for static libraries */
+#  define KPTY_EXPORT
+# elif defined(MAKE_KDECORE_LIB)
+   /* We are building this library */ 
+#  define KPTY_EXPORT KDE_EXPORT
+# else
+   /* We are using this library */ 
+#  define KPTY_EXPORT KDE_IMPORT
+# endif
+#endif
+
+# ifndef KPTY_EXPORT_DEPRECATED
+#  define KPTY_EXPORT_DEPRECATED KDE_DEPRECATED KPTY_EXPORT
+# endif
+
+#endif
new file mode 100644
--- /dev/null
+++ b/gui//src/kpty_p.h
@@ -0,0 +1,58 @@
+/* This file is part of the KDE libraries
+
+    Copyright (C) 2003,2007 Oswald Buddenhagen <ossi@kde.org>
+
+    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"
+
+#if defined(Q_OS_MAC)
+#define HAVE_UTIL_H
+#define HAVE_UTMPX
+#define _UTMPX_COMPAT
+#define HAVE_PTSNAME
+#define HAVE_SYS_TIME_H
+#else
+#define HAVE_PTY_H
+#endif
+
+#define HAVE_OPENPTY
+
+#include <QtCore/QByteArray>
+
+struct KPtyPrivate {
+    Q_DECLARE_PUBLIC(KPty)
+
+    KPtyPrivate(KPty* parent);
+    virtual ~KPtyPrivate();
+#ifndef HAVE_OPENPTY
+    bool chownpty(bool grant);
+#endif
+
+    int masterFd;
+    int slaveFd;
+    bool ownMaster:1;
+
+    QByteArray ttyName;
+
+    KPty *q_ptr;
+};
+
+#endif
new file mode 100644
--- /dev/null
+++ b/gui//src/kptydevice.cpp
@@ -0,0 +1,413 @@
+/*
+
+   This file is part of the KDE libraries
+   Copyright (C) 2007 Oswald Buddenhagen <ossi@kde.org>
+   Copyright (C) 2010 KDE e.V. <kde-ev-board@kde.org>
+     Author Adriaan de Groot <groot@kde.org>
+
+   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 "kptydevice.h"
+#include "kpty_p.h"
+#define i18n
+
+#include <QtCore/QSocketNotifier>
+
+#include <unistd.h>
+#include <errno.h>
+#include <signal.h>
+#include <termios.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#ifdef HAVE_SYS_FILIO_H
+# include <sys/filio.h>
+#endif
+#ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+#endif
+
+#if defined(Q_OS_FREEBSD) || defined(Q_OS_MAC)
+  // "the other end's output queue size" - kinda braindead, huh?
+# define PTY_BYTES_AVAILABLE TIOCOUTQ
+#elif defined(TIOCINQ)
+  // "our end's input queue size"
+# define PTY_BYTES_AVAILABLE TIOCINQ
+#else
+  // likewise. more generic ioctl (theoretically)
+# define PTY_BYTES_AVAILABLE FIONREAD
+#endif
+
+//////////////////
+// private data //
+//////////////////
+
+// Lifted from Qt. I don't think they would mind. ;)
+// Re-lift again from Qt whenever a proper replacement for pthread_once appears
+static void qt_ignore_sigpipe()
+{
+    static QBasicAtomicInt atom = Q_BASIC_ATOMIC_INITIALIZER(0);
+    if (atom.testAndSetRelaxed(0, 1)) {
+        struct sigaction noaction;
+        memset(&noaction, 0, sizeof(noaction));
+        noaction.sa_handler = SIG_IGN;
+        sigaction(SIGPIPE, &noaction, 0);
+    }
+}
+
+#define NO_INTR(ret,func) do { ret = func; } while (ret < 0 && errno == EINTR)
+
+bool KPtyDevicePrivate::_k_canRead()
+{
+    Q_Q(KPtyDevice);
+    qint64 readBytes = 0;
+
+#ifdef Q_OS_IRIX // this should use a config define, but how to check it?
+    size_t available;
+#else
+    int available;
+#endif
+    if (!::ioctl(q->masterFd(), PTY_BYTES_AVAILABLE, (char *) &available)) {
+#ifdef Q_OS_SOLARIS
+        // A Pty is a STREAMS module, and those can be activated
+        // with 0 bytes available. This happens either when ^C is
+        // pressed, or when an application does an explicit write(a,b,0)
+        // which happens in experiments fairly often. When 0 bytes are
+        // available, you must read those 0 bytes to clear the STREAMS
+        // module, but we don't want to hit the !readBytes case further down.
+        if (!available) {
+            char c;
+            // Read the 0-byte STREAMS message
+            NO_INTR(readBytes, read(q->masterFd(), &c, 0));
+            // Should return 0 bytes read; -1 is error
+            if (readBytes < 0) {
+                readNotifier->setEnabled(false);
+                emit q->readEof();
+                return false;
+            }
+            return true;
+        }
+#endif
+
+        char *ptr = readBuffer.reserve(available);
+#ifdef Q_OS_SOLARIS
+        // Even if available > 0, it is possible for read()
+        // to return 0 on Solaris, due to 0-byte writes in the stream.
+        // Ignore them and keep reading until we hit *some* data.
+        // In Solaris it is possible to have 15 bytes available
+        // and to (say) get 0, 0, 6, 0 and 9 bytes in subsequent reads.
+        // Because the stream is set to O_NONBLOCK in finishOpen(),
+        // an EOF read will return -1.
+        readBytes = 0;
+        while (!readBytes)
+#endif
+        // Useless block braces except in Solaris
+        {
+          NO_INTR(readBytes, read(q->masterFd(), ptr, available));
+        }
+        if (readBytes < 0) {
+            readBuffer.unreserve(available);
+            q->setErrorString(i18n("Error reading from PTY"));
+            return false;
+        }
+        readBuffer.unreserve(available - readBytes); // *should* be a no-op
+    }
+
+    if (!readBytes) {
+        readNotifier->setEnabled(false);
+        emit q->readEof();
+        return false;
+    } else {
+        if (!emittedReadyRead) {
+            emittedReadyRead = true;
+            emit q->readyRead();
+            emittedReadyRead = false;
+        }
+        return true;
+    }
+}
+
+bool KPtyDevicePrivate::_k_canWrite()
+{
+    Q_Q(KPtyDevice);
+
+    writeNotifier->setEnabled(false);
+    if (writeBuffer.isEmpty())
+        return false;
+
+    qt_ignore_sigpipe();
+    int wroteBytes;
+    NO_INTR(wroteBytes,
+            write(q->masterFd(),
+                  writeBuffer.readPointer(), writeBuffer.readSize()));
+    if (wroteBytes < 0) {
+        q->setErrorString(i18n("Error writing to PTY"));
+        return false;
+    }
+    writeBuffer.free(wroteBytes);
+
+    if (!emittedBytesWritten) {
+        emittedBytesWritten = true;
+        emit q->bytesWritten(wroteBytes);
+        emittedBytesWritten = false;
+    }
+
+    if (!writeBuffer.isEmpty())
+        writeNotifier->setEnabled(true);
+    return true;
+}
+
+#ifndef timeradd
+// Lifted from GLIBC
+# define timeradd(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 >= 1000000) { \
+            ++(result)->tv_sec; \
+            (result)->tv_usec -= 1000000; \
+        } \
+    } while (0)
+# 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 KPtyDevicePrivate::doWait(int msecs, bool reading)
+{
+    Q_Q(KPtyDevice);
+#ifndef __linux__
+    struct timeval etv;
+#endif
+    struct timeval tv, *tvp;
+
+    if (msecs < 0)
+        tvp = 0;
+    else {
+        tv.tv_sec = msecs / 1000;
+        tv.tv_usec = (msecs % 1000) * 1000;
+#ifndef __linux__
+        gettimeofday(&etv, 0);
+        timeradd(&tv, &etv, &etv);
+#endif
+        tvp = &tv;
+    }
+
+    while (reading ? readNotifier->isEnabled() : !writeBuffer.isEmpty()) {
+        fd_set rfds;
+        fd_set wfds;
+
+        FD_ZERO(&rfds);
+        FD_ZERO(&wfds);
+
+        if (readNotifier->isEnabled())
+            FD_SET(q->masterFd(), &rfds);
+        if (!writeBuffer.isEmpty())
+            FD_SET(q->masterFd(), &wfds);
+
+#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(q->masterFd() + 1, &rfds, &wfds, 0, tvp)) {
+        case -1:
+            if (errno == EINTR)
+                break;
+            return false;
+        case 0:
+            q->setErrorString(i18n("PTY operation timed out"));
+            return false;
+        default:
+            if (FD_ISSET(q->masterFd(), &rfds)) {
+                bool canRead = _k_canRead();
+                if (reading && canRead)
+                    return true;
+            }
+            if (FD_ISSET(q->masterFd(), &wfds)) {
+                bool canWrite = _k_canWrite();
+                if (!reading)
+                    return canWrite;
+            }
+            break;
+        }
+    }
+    return false;
+}
+
+void KPtyDevicePrivate::finishOpen(QIODevice::OpenMode mode)
+{
+    Q_Q(KPtyDevice);
+
+    q->QIODevice::open(mode);
+    fcntl(q->masterFd(), F_SETFL, O_NONBLOCK);
+    readBuffer.clear();
+    readNotifier = new QSocketNotifier(q->masterFd(), QSocketNotifier::Read, q);
+    writeNotifier = new QSocketNotifier(q->masterFd(), QSocketNotifier::Write, q);
+    QObject::connect(readNotifier, SIGNAL(activated(int)), q, SLOT(_k_canRead()));
+    QObject::connect(writeNotifier, SIGNAL(activated(int)), q, SLOT(_k_canWrite()));
+    readNotifier->setEnabled(true);
+}
+
+/////////////////////////////
+// public member functions //
+/////////////////////////////
+
+KPtyDevice::KPtyDevice(QObject *parent) :
+    QIODevice(parent),
+    KPty(new KPtyDevicePrivate(this))
+{
+}
+
+KPtyDevice::~KPtyDevice()
+{
+    close();
+}
+
+bool KPtyDevice::open(OpenMode mode)
+{
+    Q_D(KPtyDevice);
+
+    if (masterFd() >= 0)
+        return true;
+
+    if (!KPty::open()) {
+        setErrorString(i18n("Error opening PTY"));
+        return false;
+    }
+
+    d->finishOpen(mode);
+
+    return true;
+}
+
+bool KPtyDevice::open(int fd, OpenMode mode)
+{
+    Q_D(KPtyDevice);
+
+    if (!KPty::open(fd)) {
+        setErrorString(i18n("Error opening PTY"));
+        return false;
+    }
+
+    d->finishOpen(mode);
+
+    return true;
+}
+
+void KPtyDevice::close()
+{
+    Q_D(KPtyDevice);
+
+    if (masterFd() < 0)
+        return;
+
+    delete d->readNotifier;
+    delete d->writeNotifier;
+
+    QIODevice::close();
+
+    KPty::close();
+}
+
+bool KPtyDevice::isSequential() const
+{
+    return true;
+}
+
+bool KPtyDevice::canReadLine() const
+{
+    Q_D(const KPtyDevice);
+    return QIODevice::canReadLine() || d->readBuffer.canReadLine();
+}
+
+bool KPtyDevice::atEnd() const
+{
+    Q_D(const KPtyDevice);
+    return QIODevice::atEnd() && d->readBuffer.isEmpty();
+}
+
+qint64 KPtyDevice::bytesAvailable() const
+{
+    Q_D(const KPtyDevice);
+    return QIODevice::bytesAvailable() + d->readBuffer.size();
+}
+
+qint64 KPtyDevice::bytesToWrite() const
+{
+    Q_D(const KPtyDevice);
+    return d->writeBuffer.size();
+}
+
+bool KPtyDevice::waitForReadyRead(int msecs)
+{
+    Q_D(KPtyDevice);
+    return d->doWait(msecs, true);
+}
+
+bool KPtyDevice::waitForBytesWritten(int msecs)
+{
+    Q_D(KPtyDevice);
+    return d->doWait(msecs, false);
+}
+
+void KPtyDevice::setSuspended(bool suspended)
+{
+    Q_D(KPtyDevice);
+    d->readNotifier->setEnabled(!suspended);
+}
+
+bool KPtyDevice::isSuspended() const
+{
+    Q_D(const KPtyDevice);
+    return !d->readNotifier->isEnabled();
+}
+
+// protected
+qint64 KPtyDevice::readData(char *data, qint64 maxlen)
+{
+    Q_D(KPtyDevice);
+    return d->readBuffer.read(data, (int)qMin<qint64>(maxlen, KMAXINT));
+}
+
+// protected
+qint64 KPtyDevice::readLineData(char *data, qint64 maxlen)
+{
+    Q_D(KPtyDevice);
+    return d->readBuffer.readLine(data, (int)qMin<qint64>(maxlen, KMAXINT));
+}
+
+// protected
+qint64 KPtyDevice::writeData(const char *data, qint64 len)
+{
+    Q_D(KPtyDevice);
+    Q_ASSERT(len <= KMAXINT);
+
+    d->writeBuffer.write(data, len);
+    d->writeNotifier->setEnabled(true);
+    return len;
+}
+
new file mode 100644
--- /dev/null
+++ b/gui//src/kptydevice.h
@@ -0,0 +1,353 @@
+/* This file is part of the KDE libraries
+
+    Copyright (C) 2007 Oswald Buddenhagen <ossi@kde.org>
+
+    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 kptydev_h
+#define kptydev_h
+
+struct KPtyPrivate;
+struct KPtyDevicePrivate;
+
+#include "kpty.h"
+#include "kpty_p.h"
+#include <QtCore/QIODevice>
+#include <QSocketNotifier>
+
+#define Q_DECLARE_PRIVATE_MI(Class, SuperClass) \
+    inline Class##Private* d_func() { return reinterpret_cast<Class##Private *>(SuperClass::d_ptr); } \
+    inline const Class##Private* d_func() const { return reinterpret_cast<const Class##Private *>(SuperClass::d_ptr); } \
+    friend class Class##Private;
+
+/**
+ * Encapsulates KPty into a QIODevice, so it can be used with Q*Stream, etc.
+ */
+class KPtyDevice : public QIODevice, public KPty { //krazy:exclude=dpointer (via macro)
+    Q_OBJECT
+    Q_DECLARE_PRIVATE_MI(KPtyDevice, KPty)
+
+public:
+
+    /**
+     * Constructor
+     */
+    KPtyDevice(QObject *parent = 0);
+
+    /**
+     * Destructor:
+     *
+     *  If the pty is still open, it will be closed. Note, however, that
+     *  an utmp registration is @em not undone.
+     */
+    virtual ~KPtyDevice();
+
+    /**
+     * Create a pty master/slave pair.
+     *
+     * @return true if a pty pair was successfully opened
+     */
+    virtual bool open(OpenMode mode = ReadWrite | Unbuffered);
+
+    /**
+     * Open using an existing pty master. The ownership of the fd
+     * remains with the caller, i.e., close() will not close the fd.
+     *
+     * This is useful if you wish to attach a secondary "controller" to an
+     * existing pty device such as a terminal widget.
+     * Note that you will need to use setSuspended() on both devices to
+     * control which one gets the incoming data from the pty.
+     *
+     * @param fd an open pty master file descriptor.
+     * @param mode the device mode to open the pty with.
+     * @return true if a pty pair was successfully opened
+     */
+    bool open(int fd, OpenMode mode = ReadWrite | Unbuffered);
+
+    /**
+     * Close the pty master/slave pair.
+     */
+    virtual void close();
+
+    /**
+     * Sets whether the KPtyDevice monitors the pty for incoming data.
+     *
+     * When the KPtyDevice is suspended, it will no longer attempt to buffer
+     * data that becomes available from the pty and it will not emit any
+     * signals.
+     *
+     * Do not use on closed ptys.
+     * After a call to open(), the pty is not suspended. If you need to
+     * ensure that no data is read, call this function before the main loop
+     * is entered again (i.e., immediately after opening the pty).
+     */
+    void setSuspended(bool suspended);
+
+    /**
+     * Returns true if the KPtyDevice is not monitoring the pty for incoming
+     * data.
+     *
+     * Do not use on closed ptys.
+     *
+     * See setSuspended()
+     */
+    bool isSuspended() const;
+
+    /**
+     * @return always true
+     */
+    virtual bool isSequential() const;
+
+    /**
+     * @reimp
+     */
+    bool canReadLine() const;
+
+    /**
+     * @reimp
+     */
+    bool atEnd() const;
+
+    /**
+     * @reimp
+     */
+    qint64 bytesAvailable() const;
+
+    /**
+     * @reimp
+     */
+    qint64 bytesToWrite() const;
+
+    bool waitForBytesWritten(int msecs = -1);
+    bool waitForReadyRead(int msecs = -1);
+
+
+Q_SIGNALS:
+    /**
+     * Emitted when EOF is read from the PTY.
+     *
+     * Data may still remain in the buffers.
+     */
+    void readEof();
+
+protected:
+    virtual qint64 readData(char *data, qint64 maxSize);
+    virtual qint64 readLineData(char *data, qint64 maxSize);
+    virtual qint64 writeData(const char *data, qint64 maxSize);
+
+private:
+    Q_PRIVATE_SLOT(d_func(), bool _k_canRead())
+    Q_PRIVATE_SLOT(d_func(), bool _k_canWrite())
+};
+
+#define KMAXINT ((int)(~0U >> 1))
+
+/////////////////////////////////////////////////////
+// Helper. Remove when QRingBuffer becomes public. //
+/////////////////////////////////////////////////////
+
+#include <QtCore/qbytearray.h>
+#include <QtCore/qlinkedlist.h>
+
+#define CHUNKSIZE 4096
+
+class KRingBuffer
+{
+public:
+    KRingBuffer()
+    {
+        clear();
+    }
+
+    void clear()
+    {
+        buffers.clear();
+        QByteArray tmp;
+        tmp.resize(CHUNKSIZE);
+        buffers << tmp;
+        head = tail = 0;
+        totalSize = 0;
+    }
+
+    inline bool isEmpty() const
+    {
+        return buffers.count() == 1 && !tail;
+    }
+
+    inline int size() const
+    {
+        return totalSize;
+    }
+
+    inline int readSize() const
+    {
+        return (buffers.count() == 1 ? tail : buffers.first().size()) - head;
+    }
+
+    inline const char *readPointer() const
+    {
+        Q_ASSERT(totalSize > 0);
+        return buffers.first().constData() + head;
+    }
+
+    void free(int bytes)
+    {
+        totalSize -= bytes;
+        Q_ASSERT(totalSize >= 0);
+
+        forever {
+            int nbs = readSize();
+
+            if (bytes < nbs) {
+                head += bytes;
+                if (head == tail && buffers.count() == 1) {
+                    buffers.first().resize(CHUNKSIZE);
+                    head = tail = 0;
+                }
+                break;
+            }
+
+            bytes -= nbs;
+            if (buffers.count() == 1) {
+                buffers.first().resize(CHUNKSIZE);
+                head = tail = 0;
+                break;
+            }
+
+            buffers.removeFirst();
+            head = 0;
+        }
+    }
+
+    char *reserve(int bytes)
+    {
+        totalSize += bytes;
+
+        char *ptr;
+        if (tail + bytes <= buffers.last().size()) {
+            ptr = buffers.last().data() + tail;
+            tail += bytes;
+        } else {
+            buffers.last().resize(tail);
+            QByteArray tmp;
+            tmp.resize(qMax(CHUNKSIZE, bytes));
+            ptr = tmp.data();
+            buffers << tmp;
+            tail = bytes;
+        }
+        return ptr;
+    }
+
+    // release a trailing part of the last reservation
+    inline void unreserve(int bytes)
+    {
+        totalSize -= bytes;
+        tail -= bytes;
+    }
+
+    inline void write(const char *data, int len)
+    {
+        memcpy(reserve(len), data, len);
+    }
+
+    // Find the first occurrence of c and return the index after it.
+    // If c is not found until maxLength, maxLength is returned, provided
+    // it is smaller than the buffer size. Otherwise -1 is returned.
+    int indexAfter(char c, int maxLength = KMAXINT) const
+    {
+        int index = 0;
+        int start = head;
+        QLinkedList<QByteArray>::ConstIterator it = buffers.begin();
+        forever {
+            if (!maxLength)
+                return index;
+            if (index == size())
+                return -1;
+            const QByteArray &buf = *it;
+            ++it;
+            int len = qMin((it == buffers.end() ? tail : buf.size()) - start,
+                           maxLength);
+            const char *ptr = buf.data() + start;
+            if (const char *rptr = (const char *)memchr(ptr, c, len))
+                return index + (rptr - ptr) + 1;
+            index += len;
+            maxLength -= len;
+            start = 0;
+        }
+    }
+
+    inline int lineSize(int maxLength = KMAXINT) const
+    {
+        return indexAfter('\n', maxLength);
+    }
+
+    inline bool canReadLine() const
+    {
+        return lineSize() != -1;
+    }
+
+    int read(char *data, int maxLength)
+    {
+        int bytesToRead = qMin(size(), maxLength);
+        int readSoFar = 0;
+        while (readSoFar < bytesToRead) {
+            const char *ptr = readPointer();
+            int bs = qMin(bytesToRead - readSoFar, readSize());
+            memcpy(data + readSoFar, ptr, bs);
+            readSoFar += bs;
+            free(bs);
+        }
+        return readSoFar;
+    }
+
+    int readLine(char *data, int maxLength)
+    {
+        return read(data, lineSize(qMin(maxLength, size())));
+    }
+
+private:
+    QLinkedList<QByteArray> buffers;
+    int head, tail;
+    int totalSize;
+};
+
+struct KPtyDevicePrivate : public KPtyPrivate {
+    Q_DECLARE_PUBLIC(KPtyDevice)
+
+    KPtyDevicePrivate(KPty* parent) :
+        KPtyPrivate(parent),
+        emittedReadyRead(false), emittedBytesWritten(false),
+        readNotifier(0), writeNotifier(0)
+    {
+    }
+
+    bool _k_canRead();
+    bool _k_canWrite();
+
+    bool doWait(int msecs, bool reading);
+    void finishOpen(QIODevice::OpenMode mode);
+
+    bool emittedReadyRead;
+    bool emittedBytesWritten;
+    QSocketNotifier *readNotifier;
+    QSocketNotifier *writeNotifier;
+    KRingBuffer readBuffer;
+    KRingBuffer writeBuffer;
+};
+
+#endif
+
new file mode 100644
--- /dev/null
+++ b/gui//src/kptyprocess.cpp
@@ -0,0 +1,119 @@
+/*
+
+    This file is part of the KDE libraries
+
+    Copyright (C) 2007 Oswald Buddenhagen <ossi@kde.org>
+
+    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 "kptyprocess.h"
+#include "kprocess.h"
+
+#include "kptydevice.h"
+
+#include <stdlib.h>
+#include <unistd.h>
+
+//////////////////
+// private data //
+//////////////////
+
+KPtyProcess::KPtyProcess(QObject *parent) :
+    KProcess(new KPtyProcessPrivate, parent)
+{
+    Q_D(KPtyProcess);
+
+    d->pty = new KPtyDevice(this);
+    d->pty->open();
+    connect(this, SIGNAL(stateChanged(QProcess::ProcessState)),
+            SLOT(_k_onStateChanged(QProcess::ProcessState)));
+}
+
+KPtyProcess::KPtyProcess(int ptyMasterFd, QObject *parent) :
+    KProcess(new KPtyProcessPrivate, parent)
+{
+    Q_D(KPtyProcess);
+
+    d->pty = new KPtyDevice(this);
+    d->pty->open(ptyMasterFd);
+    connect(this, SIGNAL(stateChanged(QProcess::ProcessState)),
+            SLOT(_k_onStateChanged(QProcess::ProcessState)));
+}
+
+KPtyProcess::~KPtyProcess()
+{
+    Q_D(KPtyProcess);
+
+    if (state() != QProcess::NotRunning && d->addUtmp) {
+        d->pty->logout();
+        disconnect(SIGNAL(stateChanged(QProcess::ProcessState)),
+                   this, SLOT(_k_onStateChanged(QProcess::ProcessState)));
+    }
+    delete d->pty;
+}
+
+void KPtyProcess::setPtyChannels(PtyChannels channels)
+{
+    Q_D(KPtyProcess);
+
+    d->ptyChannels = channels;
+}
+
+KPtyProcess::PtyChannels KPtyProcess::ptyChannels() const
+{
+    Q_D(const KPtyProcess);
+
+    return d->ptyChannels;
+}
+
+void KPtyProcess::setUseUtmp(bool value)
+{
+    Q_D(KPtyProcess);
+
+    d->addUtmp = value;
+}
+
+bool KPtyProcess::isUseUtmp() const
+{
+    Q_D(const KPtyProcess);
+
+    return d->addUtmp;
+}
+
+KPtyDevice *KPtyProcess::pty() const
+{
+    Q_D(const KPtyProcess);
+
+    return d->pty;
+}
+
+void KPtyProcess::setupChildProcess()
+{
+    Q_D(KPtyProcess);
+
+    d->pty->setCTty();
+    if (d->addUtmp)
+      d->pty->login(getenv("USER"), getenv("DISPLAY"));
+      //d->pty->login(KUser(KUser::UseRealUserID).loginName().toLocal8Bit().data(), qgetenv("DISPLAY"));
+    if (d->ptyChannels & StdinChannel)
+        dup2(d->pty->slaveFd(), 0);
+    if (d->ptyChannels & StdoutChannel)
+        dup2(d->pty->slaveFd(), 1);
+    if (d->ptyChannels & StderrChannel)
+        dup2(d->pty->slaveFd(), 2);
+
+    KProcess::setupChildProcess();
+}
new file mode 100644
--- /dev/null
+++ b/gui//src/kptyprocess.h
@@ -0,0 +1,157 @@
+/*
+    This file is part of the KDE libraries
+
+    Copyright (C) 2007 Oswald Buddenhagen <ossi@kde.org>
+
+    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 KPTYPROCESS_H
+#define KPTYPROCESS_H
+
+#include "kprocess.h"
+#include "kprocess_p.h"
+#include "kptydevice.h"
+
+class KPtyDevice;
+class KPtyProcess;
+struct KPtyProcessPrivate;
+
+/**
+ * This class extends KProcess by support for PTYs (pseudo TTYs).
+ *
+ * The PTY is opened as soon as the class is instantiated. Verify that
+ * it was opened successfully by checking that pty()->masterFd() is not -1.
+ *
+ * The PTY is always made the process' controlling TTY.
+ * Utmp registration and connecting the stdio handles to the PTY are optional.
+ *
+ * No attempt to integrate with QProcess' waitFor*() functions was made,
+ * for it is impossible. Note that execute() does not work with the PTY, too.
+ * Use the PTY device's waitFor*() functions or use it asynchronously.
+ *
+ * @author Oswald Buddenhagen <ossi@kde.org>
+ */
+class KPtyProcess : public KProcess
+{
+    Q_OBJECT
+    Q_DECLARE_PRIVATE(KPtyProcess)
+
+public:
+    enum PtyChannelFlag {
+        NoChannels = 0, /**< The PTY is not connected to any channel. */
+        StdinChannel = 1, /**< Connect PTY to stdin. */
+        StdoutChannel = 2, /**< Connect PTY to stdout. */
+        StderrChannel = 4, /**< Connect PTY to stderr. */
+        AllOutputChannels = 6, /**< Connect PTY to all output channels. */
+        AllChannels = 7 /**< Connect PTY to all channels. */
+    };
+
+    Q_DECLARE_FLAGS(PtyChannels, PtyChannelFlag)
+
+    /**
+     * Constructor
+     */
+    explicit KPtyProcess(QObject *parent = 0);
+
+    /**
+     * Construct a process using an open pty master.
+     *
+     * @param ptyMasterFd an open pty master file descriptor.
+     *   The process does not take ownership of the descriptor;
+     *   it will not be automatically closed at any point.
+     */
+    KPtyProcess(int ptyMasterFd, QObject *parent = 0);
+
+    /**
+     * Destructor
+     */
+    virtual ~KPtyProcess();
+
+    /**
+     * Set to which channels the PTY should be assigned.
+     *
+     * This function must be called before starting the process.
+     *
+     * @param channels the output channel handling mode
+     */
+    void setPtyChannels(PtyChannels channels);
+
+    /**
+     * Query to which channels the PTY is assigned.
+     *
+     * @return the output channel handling mode
+     */
+    PtyChannels ptyChannels() const;
+
+    /**
+     * Set whether to register the process as a TTY login in utmp.
+     *
+     * Utmp is disabled by default.
+     * It should enabled for interactively fed processes, like terminal
+     * emulations.
+     *
+     * This function must be called before starting the process.
+     *
+     * @param value whether to register in utmp.
+     */
+    void setUseUtmp(bool value);
+
+    /**
+     * Get whether to register the process as a TTY login in utmp.
+     *
+     * @return whether to register in utmp
+     */
+    bool isUseUtmp() const;
+
+    /**
+     * Get the PTY device of this process.
+     *
+     * @return the PTY device
+     */
+    KPtyDevice *pty() const;
+
+protected:
+    /**
+     * @reimp
+     */
+    virtual void setupChildProcess();
+
+private:
+    Q_PRIVATE_SLOT(d_func(), void _k_onStateChanged(QProcess::ProcessState))
+};
+
+struct KPtyProcessPrivate : KProcessPrivate {
+    KPtyProcessPrivate() :
+        ptyChannels(KPtyProcess::NoChannels),
+        addUtmp(false)
+    {
+    }
+
+    void _k_onStateChanged(QProcess::ProcessState newState)
+    {
+        if (newState == QProcess::NotRunning && addUtmp)
+            pty->logout();
+    }
+
+    KPtyDevice *pty;
+    KPtyProcess::PtyChannels ptyChannels;
+    bool addUtmp : 1;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(KPtyProcess::PtyChannels)
+
+#endif
new file mode 100644
--- /dev/null
+++ b/gui//syntax_files/cpp.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<syntax>
+	<item name="keywords">
+		<pattern>
+			\b(auto|const|double|float|int|short|struct|unsigned|break|continue|else|for|long|signed|switch|void|case|default|enum|goto|register|sizeof|typedef|volatile|char|do|extern|if|return|static|union|while|asm|dynamic_cast|namespace|reinterpret_cast|try|bool|explicit|new|static_cast|typeid|catch|false|operator|template|typename|class|friend|private|this|using|const_cast|inline|public|throw|virtual|delete|mutable|protected|true|wchar_t|and|bitand|compl|not_eq|or_eq|xor_eq|and_eq|bitor|not|or|xor)\b	
+		</pattern>
+		<bold>true</bold>
+		<foreground>#0000AA</foreground>
+	</item>
+	
+	<item name="defines">
+		<pattern>#[^ ]*</pattern>
+		<foreground>#00AA00</foreground>
+	</item>
+	
+	<item name="quotes">
+		<pattern>"([^"]|\\")*"</pattern>
+		<foreground>#FF0000</foreground>
+	</item>
+	
+	<item name="single-quotes">
+		<pattern>'[^']*'</pattern>
+		<foreground>#FF0000</foreground>
+	</item>
+	
+	<item name="single-line comment">
+		<pattern>//.*</pattern>
+		<foreground>#555555</foreground>
+	</item>
+	
+	<block name="multi-line comment">
+		<startPattern>(?!//)/\*</startPattern>
+		<endPattern>\*/</endPattern>
+		<foreground>#555555</foreground>
+	</block>
+	
+	<bracket name="{}bracket">
+		<startPattern>\{</startPattern>
+		<endPattern>\}</endPattern>
+		<background>#ffff00</background>
+	</bracket>
+	
+	<bracket name="()bracket">
+		<startPattern>\(</startPattern>
+		<endPattern>\)</endPattern>
+		<background>#ffff00</background>
+	</bracket>
+	
+	<bracket name="[]bracket">
+		<startPattern>\[</startPattern>
+		<endPattern>\]</endPattern>
+		<background>#ffff00</background>
+	</bracket>
+	
+	
+</syntax>
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/gui//syntax_files/h.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<syntax>
+	<item name="keywords">
+		<pattern>
+			\b(auto|const|double|float|int|short|struct|unsigned|break|continue|else|for|long|signed|switch|void|case|default|enum|goto|register|sizeof|typedef|volatile|char|do|extern|if|return|static|union|while|asm|dynamic_cast|namespace|reinterpret_cast|try|bool|explicit|new|static_cast|typeid|catch|false|operator|template|typename|class|friend|private|this|using|const_cast|inline|public|throw|virtual|delete|mutable|protected|true|wchar_t|and|bitand|compl|not_eq|or_eq|xor_eq|and_eq|bitor|not|or|xor)\b	
+		</pattern>
+		<bold>true</bold>
+		<foreground>#0000AA</foreground>
+	</item>
+	
+	<item name="defines">
+		<pattern>#[^ ]*</pattern>
+		<foreground>#00AA00</foreground>
+	</item>
+	
+	<item name="quotes">
+		<pattern>"([^"]|\\")*"</pattern>
+		<foreground>#FF0000</foreground>
+	</item>
+	
+	<item name="single-quotes">
+		<pattern>'[^']*'</pattern>
+		<foreground>#FF0000</foreground>
+	</item>
+	
+	<item name="single-line comment">
+		<pattern>//.*</pattern>
+		<foreground>#555555</foreground>
+	</item>
+	
+	<block name="multi-line comment">
+		<startPattern>(?!//)/\*</startPattern>
+		<endPattern>\*/</endPattern>
+		<foreground>#555555</foreground>
+	</block>
+	
+	<bracket name="{}bracket">
+		<startPattern>\{</startPattern>
+		<endPattern>\}</endPattern>
+		<background>#ffff00</background>
+	</bracket>
+	
+	<bracket name="()bracket">
+		<startPattern>\(</startPattern>
+		<endPattern>\)</endPattern>
+		<background>#ffff00</background>
+	</bracket>
+	
+	<bracket name="[]bracket">
+		<startPattern>\[</startPattern>
+		<endPattern>\]</endPattern>
+		<background>#ffff00</background>
+	</bracket>
+	
+	
+</syntax>
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/gui//syntax_files/m.xml
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<syntax>
+	<item name="keywords">
+		<pattern>
+			\b(all_va_args|break|case|continue|else|elseif|end_unwind_protect|global|gplot|gsplot|otherwise|persistent|replot|return|static|until|unwind_protect|unwind_protect_cleanup|varargin|varargout|casesen|cd|chdir|clear|dbclear|dbstatus|dbstop|dbtype|dbwhere|diary|echo|edit_history|__end__|format|gset|gshow|help|history|hold|iskeyword|isvarname|load|ls|mark_as_command|mislocked|mlock|more|munlock|run_history|save|set|show|type|unmark_command|which|who|whos|for|endfor|if|endif|do|until|while|endwhile|function|endfunction|switch|endswitch|try|end_try_catch|end)\b	
+		</pattern>
+		<bold>true</bold>
+	</item>
+	
+	<item name="functions">
+		<pattern>
+			\b(argv|e|eps|false|F_DUPFD|F_GETFD|F_GETFL|filesep|F_SETFD|F_SETFL|i|I|inf|Inf|j|J|NA|nan|NaN|O_APPEND|O_ASYNC|O_CREAT|OCTAVE_HOME|OCTAVE_VERSION|O_EXCL|O_NONBLOCK|O_RDONLY|O_RDWR|O_SYNC|O_TRUNC|O_WRONLY|pi|program_invocation_name|program_name|P_tmpdir|realmax|realmin|SEEK_CUR|SEEK_END|SEEK_SET|SIG|stderr|stdin|stdout|true|ans|automatic_replot|beep_on_error|completion_append_char|crash_dumps_octave_core|current_script_file_name|debug_on_error|debug_on_interrupt|debug_on_warning|debug_symtab_lookups|DEFAULT_EXEC_PATH|DEFAULT_LOADPATH|default_save_format|echo_executing_commands|EDITOR|EXEC_PATH|FFTW_WISDOM_PROGRAM|fixed_point_format|gnuplot_binary|gnuplot_command_axes|gnuplot_command_end|gnuplot_command_plot|gnuplot_command_replot|gnuplot_command_splot|gnuplot_command_title|gnuplot_command_using|gnuplot_command_with|gnuplot_has_frames|history_file|history_size|ignore_function_time_stamp|IMAGEPATH|INFO_FILE|INFO_PROGRAM|__kluge_procbuf_delay__|LOADPATH|MAKEINFO_PROGRAM|max_recursion_depth|octave_core_file_format|octave_core_file_limit|octave_core_file_name|output_max_field_width|output_precision|page_output_immediately|PAGER|page_screen_output|print_answer_id_name|print_empty_dimensions|print_rhs_assign_val|PS1|PS2|PS4|save_header_format_string|save_precision|saving_history|sighup_dumps_octave_core|sigterm_dumps_octave_core|silent_functions|split_long_rows|string_fill_char|struct_levels_to_print|suppress_verbose_help_message|variables_can_hide_functions|warn_assign_as_truth_value|warn_divide_by_zero|warn_empty_list_elements|warn_fortran_indexing|warn_function_name_clash|warn_future_time_stamp|warn_imag_to_real|warn_matlab_incompatible|warn_missing_semicolon|warn_neg_dim_as_zero|warn_num_to_str|warn_precedence_change|warn_reload_forces_clear|warn_resize_on_range_error|warn_separator_insert|warn_single_quote_string|warn_str_to_num|warn_undefined_return_values|warn_variable_switch_label|whos_line_format|synchrotron_1|synchrotron_2|syndtable|taylorcoeff|transport_2|transport_3|transport_4|transport_5|trisolve|waitbar|xmlread|zeta|zeta_int|aar|aarmam|ac2poly|ac2rc|acorf|acovf|addpath|ademodce|adim|adsmax|amodce|anderson_darling_cdf|anderson_darling_test|anovan|apkconst|append_save|applylut|ar2poly|ar2rc|arburg|arcext|arfit2|ar_spa|aryule|assert|au|aucapture|auload|auplot|aurecord|ausave|autumn|average_moments|awgn|azimuth|BandToFull|BandToSparse|base64encode|battery|bchpoly|bestblk|best_dir|best_dir_cov|betaln|bfgs|bfgsmin_example|bi2de|biacovf|bilinear|bisdemo|bispec|biterr|blkdiag|blkproc|bmpwrite|bone|bound_convex|boxcar|boxplot|brighten|bs_gradient|butter|buttord|bwborder|bweuler|bwlabel|bwmorph|bwselect|calendar|cceps|cdiff|cellstr|char|cheb|cheb1ord|cheb2ord|chebwin|cheby1|cheby2|chirp|clf|clip|cmpermute|cmunique|cohere|col2im|colfilt|colorgradient|comms|compand|complex|concat|conndef|content|contents|Contents|contourf|convhull|convmtx|cool|copper|corr2|cosets|count|covm|cplxpair|cquadnd|create_lookup_table|crule|crule2d|crule2dgen|csape|csapi|csd|csvread|csvwrite|ctranspose|cumtrapz|czt|d2_min|datenum|datestr|datevec|dct|dct2|dctmtx|de2bi|deal|decimate|decode|deg2rad|del2|delaunay|delaunay3|delta_method|demo|demodmap|deriv|detrend|dfdp|dftmtx|dhbar|dilate|dispatch|distance|dlmread|dlmwrite|dos|double|drawnow|durlev|dxfwrite|edge|edit|ellip|ellipdemo|ellipj|ellipke|ellipord|__ellip_ws|__ellip_ws_min|encode|eomday|erode|example|ExampleEigenValues|ExampleGenEigenValues|expdemo|expfit|eyediagram|factor|factorial|fail|fcnchk|feedback|fem_test|ff2n|fftconv2|fieldnames|fill|fill3|filter2|filtfilt|filtic|findsym|fir1|fir2|fixedpoint|flag|flag_implicit_samplerate|flattopwin|flix|float|fmin|fminbnd|fmins|fminunc|fnder|fnplt|fnval|fplot|freqs|freqs_plot|fsort|fullfact|FullToBand|funm|fzero|gammaln|gapTest|gaussian|gausswin|gconv|gconvmtx|gdeconv|gdftmtx|gen2par|geomean|getfield|getfields|gfft|gftable|gfweight|gget|gifft|ginput|gmm_estimate|gmm_example|gmm_obj|gmm_results|gmm_variance|gmm_variance_inefficient|gquad|gquad2d|gquad2d6|gquad2dgen|gquad6|gquadnd|grace_octave_path|gradient|grayslice|grep|grid|griddata|groots|grpdelay|grule|grule2d|grule2dgen|hadamard|hammgen|hankel|hann|harmmean|hilbert|histeq|histfit|histo|histo2|histo3|histo4|hot|hsv|hup|idct|idct2|idplot|idsim|ifftshift|im2bw|im2col|imadjust|imginfo|imhist|imnoise|impad|impz|imread|imrotate|imshear|imtranslate|imwrite|innerfun|inputname|interp|interp1|interp2|interpft|intersect|invest0|invest1|invfdemo|invfreq|invfreqs|invfreqz|inz|irsa_act|irsa_actcore|irsa_check|irsa_dft|irsa_dftfp|irsa_genreal|irsa_idft|irsa_isregular|irsa_jitsp|irsa_mdsp|irsa_normalize|irsa_plotdft|irsa_resample|irsa_rgenreal|isa|isbw|isdir|isequal|isfield|isgray|isind|ismember|isprime|isrgb|issparse|isunix|jet|kaiser|kaiserord|lambertw|lattice|lauchli|leasqr|leasqrdemo|legend|legendre|levinson|lin2mu|line_min|lloyds|lookup|lookup_table|lpc|lp_test|mad|magic|makelut|MakeShears|map|mat2gray|mat2str|mdsmax|mean2|medfilt2|meshc|minimize|minpol|mkpp|mktheta|mle_estimate|mle_example|mle_obj|mle_results|mle_variance|modmap|mu2lin|mvaar|mvar|mvfilter|mvfreqz|myfeval|nanmax|nanmean|nanmedian|nanmin|nanstd|nansum|ncauer|nchoosek|ncrule|ndims|nelder_mead_min|newmark|nlfilter|nlnewmark|__nlnewmark_fcn__|nmsmax|nonzeros|normplot|now|nrm|nthroot|nze|OCTAVE_FORGE_VERSION|ode23|ode45|ode78|optimset|ordfilt2|orient|pacf|padarray|parameterize|parcor|pareto|pascal|patch|pburg|pcg|pchip|pcolor|pcr|peaks|penddot|pendulum|perms|pie|pink|plot3|__plt3__|poly2ac|poly2ar|poly_2_ex|poly2mask|poly2rc|poly2sym|poly2th|polyarea|polyconf|polyder|polyderiv|polygcd|polystab|__power|ppval|prctile|prettyprint|prettyprint_c|primes|princomp|print|prism|proplan|pulstran|pwelch|pyulear|qaskdeco|qaskenco|qtdecomp|qtgetblk|qtsetblk|quad2dc|quad2dcgen|quad2dg|quad2dggen|quadc|quadg|quadl|quadndg|quantiz|quiver|rad2deg|rainbow|randerr|randint|randsrc|rat|rats|rc2ac|rc2ar|rc2poly|rceps|read_options|read_pdb|rectpuls|resample|rgb2gray|rk2fixed|rk4fixed|rk8fixed|rmfield|rmle|rmpath|roicolor|rosser|rotparams|rotv|rref|rsdecof|rsencof|rsgenpoly|samin_example|save_vrml|sbispec|scale_data|scatter|scatterplot|select_3D_points|selmo|setdiff|setfield|setfields|setxor|sftrans|sgolay|sgolayfilt|sinvest1|slurp_file|sortrows|sound|soundsc|spdiags|specgram|speed|speye|spfun|sphcat|spline|splot|spones|sprand|sprandn|spring|spstats|spsum|sp_test|sptest|spvcat|spy|std2|stem|str2double|strcmpi|stretchlim|strfind|strmatch|strncmp|strncmpi|strsort|strtok|strtoz|struct|strvcat|summer|sumskipnan|surf|surfc|sym2poly|symerr|symfsolve|tabulate|tar|temp_name|test|test_d2_min_1|test_d2_min_2|test_d2_min_3|test_ellipj|test_fminunc_1|testimio|test_inline_1|test_min_1|test_min_2|test_min_3|test_min_4|test_minimize_1|test_nelder_mead_min_1|test_nelder_mead_min_2|test_sncndn|test_struct|test_vmesh|test_vrml_faces|test_wpolyfit|text|textread|tf2zp|tfe|thfm|tics|toeplitz|toggle_grace_use|transpose|trapz|triang|tril|trimmean|tripuls|trisolve|triu|tsademo|tsearchdemo|ucp|uintlut|unique|unix|unmkpp|unscale_parameters|vec2mat|view|vmesh|voronoi|voronoin|vrml_arrow|vrml_Background|vrml_browse|vrml_cyl|vrml_demo_tutorial_1|vrml_demo_tutorial_2|vrml_demo_tutorial_3|vrml_demo_tutorial_4|vrml_ellipsoid|vrml_faces|vrml_flatten|vrml_frame|vrml_group|vrml_kill|vrml_lines|vrml_material|vrml_parallelogram|vrml_PointLight|vrml_points|vrml_select_points|vrml_surf|vrml_text|vrml_thick_surf|vrml_transfo|wavread|wavwrite|weekday|wgn|white|wilkinson|winter|wpolyfit|wpolyfitdemo|write_pdb|wsolve|xcorr|xcorr2|xcov|xlsread|xmlwrite|y2res|zero_count|zoom|zp2tf|zplane|shell_cmd|show|sign|sin|sinh|size|sizeof|sleep|sort|source|splice|sprintf|sqrt|squeeze|sscanf|stat|str2func|streamoff|struct|struct2cell|sum|sumsq|symlink|system|tan|tanh|tilde_expand|tmpfile|tmpnam|toascii|__token_count__|tolower|toupper|type|typeinfo|uint16|uint32|uint64|uint8|umask|undo_string_escapes|unlink|unmark_command|usage|usleep|va_arg|va_start|vectorize|vertcat|vr_val|waitpid|warning|warranty|which|who|whos|zeros|airy|balance|besselh|besseli|besselj|besselk|bessely|betainc|chol|colloc|daspk|daspk_options|dasrt|dasrt_options|dassl|dassl_options|det|eig|endgrent|endpwent|expm|fft|fft2|fftn|fftw_wisdom|filter|find|fsolve|fsolve_options|gammainc|gcd|getgrent|getgrgid|getgrnam|getpwent|getpwnam|getpwuid|getrusage|givens|gmtime|hess|ifft|ifft2|ifftn|inv|inverse|kron|localtime|lpsolve|lpsolve_options|lsode|lsode_options|lu|max|min|minmax|mktime|odessa|odessa_options|pinv|qr|quad|quad_options|qz|rand|randn|schur|setgrent|setpwent|sort|sqrtm|strftime|strptime|svd|syl|time|abcddim|__abcddims__|acot|acoth|acsc|acsch|analdemo|anova|arch_fit|arch_rnd|arch_test|are|arma_rnd|asctime|asec|asech|autocor|autocov|autoreg_matrix|axis|axis2dlim|__axis_label__|bar|bartlett|bartlett_test|base2dec|bddemo|beep|bessel|beta|beta_cdf|betai|beta_inv|beta_pdf|beta_rnd|bin2dec|bincoeff|binomial_cdf|binomial_inv|binomial_pdf|binomial_rnd|bitcmp|bitget|bitset|blackman|blanks|bode|bode_bounds|__bodquist__|bottom_title|bug_report|buildssic|c2d|cart2pol|cart2sph|cauchy_cdf|cauchy_inv|cauchy_pdf|cauchy_rnd|cellidx|center|chisquare_cdf|chisquare_inv|chisquare_pdf|chisquare_rnd|chisquare_test_homogeneity|chisquare_test_independence|circshift|clock|cloglog|close|colormap|columns|com2str|comma|common_size|commutation_matrix|compan|complement|computer|cond|contour|controldemo|conv|cor|corrcoef|cor_test|cot|coth|cov|cputime|create_set|cross|csc|csch|ctime|ctrb|cut|d2c|damp|dare|date|dcgain|deal|deblank|dec2base|dec2bin|dec2hex|deconv|delete|DEMOcontrol|demoquat|detrend|dezero|dgkfdemo|dgram|dhinfdemo|diff|diffpara|dir|discrete_cdf|discrete_inv|discrete_pdf|discrete_rnd|dkalman|dlqe|dlqg|dlqr|dlyap|dmr2d|dmult|dot|dre|dump_prefs|duplication_matrix|durbinlevinson|empirical_cdf|empirical_inv|empirical_pdf|empirical_rnd|erfinv|__errcomm__|errorbar|__errplot__|etime|exponential_cdf|exponential_inv|exponential_pdf|exponential_rnd|f_cdf|fftconv|fftfilt|fftshift|figure|fileparts|findstr|f_inv|fir2sys|flipdim|fliplr|flipud|flops|f_pdf|fractdiff|frdemo|freqchkw|__freqresp__|freqz|freqz_plot|f_rnd|f_test_regression|fullfile|fv|fvl|gamma_cdf|gammai|gamma_inv|gamma_pdf|gamma_rnd|geometric_cdf|geometric_inv|geometric_pdf|geometric_rnd|gls|gram|gray|gray2ind|grid|h2norm|h2syn|hamming|hankel|hanning|hex2dec|hilb|hinf_ctr|hinfdemo|hinfnorm|hinfsyn|hinfsyn_chk|hinfsyn_ric|hist|hotelling_test|hotelling_test_2|housh|hsv2rgb|hurst|hypergeometric_cdf|hypergeometric_inv|hypergeometric_pdf|hypergeometric_rnd|image|imagesc|impulse|imshow|ind2gray|ind2rgb|ind2sub|index|int2str|intersection|invhilb|iqr|irr|isa|is_abcd|is_bool|is_complex|is_controllable|isdefinite|is_detectable|is_dgkf|is_digital|is_duplicate_entry|is_global|is_leap_year|isletter|is_list|is_matrix|is_observable|ispc|is_sample|is_scalar|isscalar|is_signal_list|is_siso|is_square|issquare|is_stabilizable|is_stable|isstr|is_stream|is_struct|is_symmetric|issymmetric|isunix|is_vector|isvector|jet707|kendall|kolmogorov_smirnov_cdf|kolmogorov_smirnov_test|kolmogorov_smirnov_test_2|kruskal_wallis_test|krylov|krylovb|kurtosis|laplace_cdf|laplace_inv|laplace_pdf|laplace_rnd|lcm|lin2mu|listidx|list_primes|loadaudio|loadimage|log2|logical|logistic_cdf|logistic_inv|logistic_pdf|logistic_regression|logistic_regression_derivatives|logistic_regression_likelihood|logistic_rnd|logit|loglog|loglogerr|logm|lognormal_cdf|lognormal_inv|lognormal_pdf|lognormal_rnd|logspace|lower|lqe|lqg|lqr|lsim|ltifr|lyap|mahalanobis|manova|mcnemar_test|mean|meansq|median|menu|mesh|meshdom|meshgrid|minfo|mod|moddemo|moment|mplot|mu2lin|multiplot|nargchk|nextpow2|nichols|norm|normal_cdf|normal_inv|normal_pdf|normal_rnd|not|nper|npv|ntsc2rgb|null|num2str|nyquist|obsv|ocean|ols|oneplot|ord2|orth|__outlist__|pack|packedform|packsys|parallel|paren|pascal_cdf|pascal_inv|pascal_pdf|pascal_rnd|path|periodogram|perror|place|playaudio|plot|plot_border|__plr__|__plr1__|__plr2__|__plt__|__plt1__|__plt2__|__plt2mm__|__plt2mv__|__plt2ss__|__plt2vm__|__plt2vv__|__pltopt__|__pltopt1__|pmt|poisson_cdf|poisson_inv|poisson_pdf|poisson_rnd|pol2cart|polar|poly|polyder|polyderiv|polyfit|polyinteg|polyout|polyreduce|polyval|polyvalm|popen2|postpad|pow2|ppplot|prepad|probit|prompt|prop_test_2|pv|pvl|pzmap|qconj|qcoordinate_plot|qderiv|qderivmat|qinv|qmult|qqplot|qtrans|qtransv|qtransvmat|quaternion|qzhess|qzval|randperm|range|rank|ranks|rate|record|rectangle_lw|rectangle_sw|rem|repmat|residue|rgb2hsv|rgb2ind|rgb2ntsc|rindex|rldemo|rlocus|roots|rot90|rotdim|rotg|rows|run_cmd|run_count|run_test|saveaudio|saveimage|sec|sech|semicolon|semilogx|semilogxerr|semilogy|semilogyerr|series|setaudio|setstr|shg|shift|shiftdim|sign_test|sinc|sinetone|sinewave|skewness|sombrero|sortcom|spearman|spectral_adf|spectral_xdf|spencer|sph2cart|split|ss|ss2sys|ss2tf|ss2zp|stairs|starp|statistics|std|stdnormal_cdf|stdnormal_inv|stdnormal_pdf|stdnormal_rnd|step|__stepimp__|stft|str2mat|str2num|strappend|strcat|strcmp|strerror|strjust|strrep|struct_contains|struct_elements|studentize|sub2ind|subplot|substr|subwindow|swap|swapcols|swaprows|sylvester_matrix|synthesis|sys2fir|sys2ss|sys2tf|sys2zp|sysadd|sysappend|syschnames|__syschnamesl__|syschtsam|__sysconcat__|sysconnect|syscont|__syscont_disc__|__sysdefioname__|__sysdefstname__|sysdimensions|sysdisc|sysdup|sysgetsignals|sysgettsam|sysgettype|sysgroup|__sysgroupn__|sysidx|sysmin|sysmult|sysout|sysprune|sysreorder|sysrepdemo|sysscale|syssetsignals|syssub|sysupdate|table|t_cdf|tempdir|tempname|texas_lotto|tf|tf2ss|tf2sys|__tf2sysl__|tf2zp|__tfl__|tfout|tic|t_inv|title|toc|toeplitz|top_title|t_pdf|trace|triangle_lw|triangle_sw|tril|triu|t_rnd|t_test|t_test_2|t_test_regression|tzero|tzero2|ugain|uniform_cdf|uniform_inv|uniform_pdf|uniform_rnd|union|unix|unpacksys|unwrap|upper|u_test|values|vander|var|var_test|vec|vech|version|vol|weibull_cdf|weibull_inv|weibull_pdf|weibull_rnd|welch_test|wgt1o|wiener_rnd|wilcoxon_test|xlabel|xor|ylabel|yulewalker|zgfmul|zgfslv|zginit|__zgpbal__|zgreduce|zgrownorm|zgscal|zgsgiv|zgshsr|zlabel|zp|zp2ss|__zp2ssg2__|zp2sys|zp2tf|zpout|z_test)\b	
+		</pattern>
+		<foreground>#0000BB</foreground>
+		<bold>false</bold>
+	</item>
+	
+	<item name="variables">
+		<pattern>[a-zA-Z_][a-zA-Z_0-9]*'?</pattern>
+		<bold>false</bold>
+	</item>
+	
+	<item name="numbers">
+		<pattern>(\d+(\.\d+)?|\.\d+)([eE][+-]?\d+)?[ij]?</pattern>
+		<foreground>#BB0000</foreground>
+		<bold>false</bold>
+	</item>
+	
+	<item name="quotes">
+		<pattern>"([^"]|\\")*"</pattern>
+		<foreground>#FF0000</foreground>
+	</item>
+	
+	<item name="single-quotes">
+		<pattern>'([^']|\\')*'</pattern>
+		<foreground>#FF0000</foreground>
+	</item>
+	
+	<block name="multi-line comment #{">
+		<startPattern>#\{</startPattern>
+		<endPattern>#\}</endPattern>
+		<foreground>#008800</foreground>
+	</block>
+	
+	<block name="multi-line comment %{">
+		<startPattern>%\{</startPattern>
+		<endPattern>%\}</endPattern>
+		<foreground>#008800</foreground>
+	</block>
+	
+	<item name="single-line comment">
+		<pattern>[#|%].*</pattern>
+		<foreground>#008800</foreground>
+	</item>
+	
+	<bracket name="{}bracket">
+		<startPattern>\{</startPattern>
+		<endPattern>\}</endPattern>
+		<background>#ffff00</background>
+	</bracket>
+	
+	<bracket name="()bracket">
+		<startPattern>\(</startPattern>
+		<endPattern>\)</endPattern>
+		<background>#ffff00</background>
+	</bracket>
+	
+	<bracket name="[]bracket">
+		<startPattern>\[</startPattern>
+		<endPattern>\]</endPattern>
+		<background>#ffff00</background>
+	</bracket>
+	
+	
+</syntax>
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/gui//syntax_files/sh.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<syntax>
+	<item name="comment">
+		<pattern>#[^ ]*</pattern>
+		<foreground>#00AA00</foreground>
+	</item>
+	
+	<item name="quotes">
+		<pattern>"[^"]*"</pattern>
+		<foreground>#FF0000</foreground>
+	</item>
+	
+	<item name="single-quotes">
+		<pattern>'[^']*'</pattern>
+		<foreground>#FF0000</foreground>
+	</item>
+</syntax>
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/gui/Doxyfile
@@ -0,0 +1,1661 @@
+# Doxyfile 1.7.1
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+#       TAG = value [value, ...]
+# For lists items can also be appended using:
+#       TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file 
+# that follow. The default is UTF-8 which is also the encoding used for all 
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the 
+# iconv built into libc) for the transcoding. See 
+# http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded 
+# by quotes) that should identify the project.
+
+PROJECT_NAME           = Quint
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. 
+# This could be handy for archiving the generated documentation or 
+# if some version control system is used.
+
+PROJECT_NUMBER         = 0.4
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) 
+# base path where the generated documentation will be put. 
+# If a relative path is entered, it will be relative to the location 
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = /home/jacob/Desktop/Quint-Documentation
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 
+# 4096 sub-directories (in 2 levels) under the output directory of each output 
+# format and will distribute the generated files over these directories. 
+# Enabling this option can be useful when feeding doxygen a huge amount of 
+# source files, where putting all generated files in the same directory would 
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS         = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all 
+# documentation generated by doxygen is written. Doxygen will use this 
+# information to generate all constant output in the proper language. 
+# The default language is English, other supported languages are: 
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, 
+# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, 
+# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English 
+# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, 
+# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, 
+# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will 
+# include brief member descriptions after the members that are listed in 
+# the file and class documentation (similar to JavaDoc). 
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend 
+# the brief description of a member or function before the detailed description. 
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the 
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator 
+# that is used to form the text in various listings. Each string 
+# in this list, if found as the leading text of the brief description, will be 
+# stripped from the text and the result after processing the whole list, is 
+# used as the annotated text. Otherwise, the brief description is used as-is. 
+# If left blank, the following values are used ("$name" is automatically 
+# replaced with the name of the entity): "The $name class" "The $name widget" 
+# "The $name file" "is" "provides" "specifies" "contains" 
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF       = "The $name class" \
+                         "The $name widget" \
+                         "The $name file" \
+                         is \
+                         provides \
+                         specifies \
+                         contains \
+                         represents \
+                         a \
+                         an \
+                         the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then 
+# Doxygen will generate a detailed section even if there is only a brief 
+# description.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all 
+# inherited members of a class in the documentation of that class as if those 
+# members were ordinary class members. Constructors, destructors and assignment 
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full 
+# path before files name in the file list and in the header files. If set 
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES        = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag 
+# can be used to strip a user-defined part of the path. Stripping is 
+# only done if one of the specified strings matches the left-hand part of 
+# the path. The tag can be used to show relative paths in the file list. 
+# If left blank the directory from which doxygen is run is used as the 
+# path to strip.
+
+STRIP_FROM_PATH        = 
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of 
+# the path mentioned in the documentation of a class, which tells 
+# the reader which header file to include in order to use a class. 
+# If left blank only the name of the header file containing the class 
+# definition is used. Otherwise one should specify the include paths that 
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH    = 
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter 
+# (but less readable) file names. This can be useful is your file systems 
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen 
+# will interpret the first line (until the first dot) of a JavaDoc-style 
+# comment as the brief description. If set to NO, the JavaDoc 
+# comments will behave just like regular Qt-style comments 
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF      = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will 
+# interpret the first line (until the first dot) of a Qt-style 
+# comment as the brief description. If set to NO, the comments 
+# will behave just like regular Qt-style comments (thus requiring 
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF           = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen 
+# treat a multi-line C++ special comment block (i.e. a block of //! or /// 
+# comments) as a brief description. This used to be the default behaviour. 
+# The new default is to treat a multi-line C++ comment block as a detailed 
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented 
+# member inherits the documentation from any documented member that it 
+# re-implements.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce 
+# a new page for each member. If set to NO, the documentation of a member will 
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. 
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE               = 8
+
+# This tag can be used to specify a number of aliases that acts 
+# as commands in the documentation. An alias has the form "name=value". 
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to 
+# put the command \sideeffect (or @sideeffect) in the documentation, which 
+# will result in a user-defined paragraph with heading "Side Effects:". 
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES                = 
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C 
+# sources only. Doxygen will then generate output that is more tailored for C. 
+# For instance, some of the names that are used will be different. The list 
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C  = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java 
+# sources only. Doxygen will then generate output that is more tailored for 
+# Java. For instance, namespaces will be presented as packages, qualified 
+# scopes will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran 
+# sources only. Doxygen will then generate output that is more tailored for 
+# Fortran.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL 
+# sources. Doxygen will then generate output that is tailored for 
+# VHDL.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it 
+# parses. With this tag you can assign which parser to use for a given extension. 
+# Doxygen has a built-in mapping, but you can override or extend it using this 
+# tag. The format is ext=language, where ext is a file extension, and language 
+# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C, 
+# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make 
+# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C 
+# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions 
+# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen.
+
+EXTENSION_MAPPING      = 
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want 
+# to include (a tag file for) the STL sources as input, then you should 
+# set this tag to YES in order to let doxygen match functions declarations and 
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. 
+# func(std::string) {}). This also make the inheritance and collaboration 
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to 
+# enable parsing support.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. 
+# Doxygen will parse them like normal C++ but will assume all classes use public 
+# instead of private inheritance when no explicit protection keyword is present.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate getter 
+# and setter methods for a property. Setting this option to YES (the default) 
+# will make doxygen to replace the get and set methods by a property in the 
+# documentation. This will only work if the methods are indeed getting or 
+# setting a simple type. If this is not the case, or you want to show the 
+# methods anyway, you should set this option to NO.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC 
+# tag is set to YES, then doxygen will reuse the documentation of the first 
+# member in the group (if any) for the other members of the group. By default 
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of 
+# the same type (for instance a group of public functions) to be put as a 
+# subgroup of that type (e.g. under the Public Functions section). Set it to 
+# NO to prevent subgrouping. Alternatively, this can be done per class using 
+# the \nosubgrouping command.
+
+SUBGROUPING            = YES
+
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum 
+# is documented as struct, union, or enum with the name of the typedef. So 
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct 
+# with name TypeT. When disabled the typedef will appear as a member of a file, 
+# namespace, or class. And the struct will be named TypeS. This can typically 
+# be useful for C code in case the coding convention dictates that all compound 
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to 
+# determine which symbols to keep in memory and which to flush to disk. 
+# When the cache is full, less often used symbols will be written to disk. 
+# For small to medium size projects (<1000 input files) the default value is 
+# probably good enough. For larger projects a too small cache size can cause 
+# doxygen to be busy swapping symbols to and from disk most of the time 
+# causing a significant performance penality. 
+# If the system has enough physical memory increasing the cache will improve the 
+# performance by keeping more symbols in memory. Note that the value works on 
+# a logarithmic scale so increasing the size by one will rougly double the 
+# memory usage. The cache size is given by this formula: 
+# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, 
+# corresponding to a cache size of 2^16 = 65536 symbols
+
+SYMBOL_CACHE_SIZE      = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in 
+# documentation are documented, even if no documentation was available. 
+# Private class members and static file members will be hidden unless 
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL            = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class 
+# will be included in the documentation.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file 
+# will be included in the documentation.
+
+EXTRACT_STATIC         = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) 
+# defined locally in source files will be included in the documentation. 
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. When set to YES local 
+# methods, which are defined in the implementation section but not in 
+# the interface are included in the documentation. 
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be 
+# extracted and appear in the documentation as a namespace called 
+# 'anonymous_namespace{file}', where file will be replaced with the base 
+# name of the file that contains the anonymous namespace. By default 
+# anonymous namespace are hidden.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all 
+# undocumented members of documented classes, files or namespaces. 
+# If set to NO (the default) these members will be included in the 
+# various overviews, but no documentation section is generated. 
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all 
+# undocumented classes that are normally visible in the class hierarchy. 
+# If set to NO (the default) these classes will be included in the various 
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all 
+# friend (class|struct|union) declarations. 
+# If set to NO (the default) these declarations will be included in the 
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any 
+# documentation blocks found inside the body of a function. 
+# If set to NO (the default) these blocks will be appended to the 
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation 
+# that is typed after a \internal command is included. If the tag is set 
+# to NO (the default) then the documentation will be excluded. 
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate 
+# file names in lower-case letters. If set to YES upper-case letters are also 
+# allowed. This is useful if you have classes or files whose names only differ 
+# in case and if your file system supports case sensitive file names. Windows 
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES       = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen 
+# will show members with their full class and namespace scopes in the 
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen 
+# will put a list of the files that are included by a file in the documentation 
+# of that file.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen 
+# will list include files with double quotes in the documentation 
+# rather than with sharp brackets.
+
+FORCE_LOCAL_INCLUDES   = NO
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] 
+# is inserted in the documentation for inline members.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen 
+# will sort the (detailed) documentation of file and class members 
+# alphabetically by member name. If set to NO the members will appear in 
+# declaration order.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the 
+# brief documentation of file, namespace and class members alphabetically 
+# by member name. If set to NO (the default) the members will appear in 
+# declaration order.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen 
+# will sort the (brief and detailed) documentation of class members so that 
+# constructors and destructors are listed first. If set to NO (the default) 
+# the constructors will appear in the respective orders defined by 
+# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. 
+# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO 
+# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the 
+# hierarchy of group names into alphabetical order. If set to NO (the default) 
+# the group names will appear in their defined order.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be 
+# sorted by fully-qualified names, including namespaces. If set to 
+# NO (the default), the class list will be sorted only by class name, 
+# not including the namespace part. 
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. 
+# Note: This option applies only to the class list, not to the 
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or 
+# disable (NO) the todo list. This list is created by putting \todo 
+# commands in the documentation.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or 
+# disable (NO) the test list. This list is created by putting \test 
+# commands in the documentation.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or 
+# disable (NO) the bug list. This list is created by putting \bug 
+# commands in the documentation.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or 
+# disable (NO) the deprecated list. This list is created by putting 
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional 
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS       = 
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines 
+# the initial value of a variable or define consists of for it to appear in 
+# the documentation. If the initializer consists of more lines than specified 
+# here it will be hidden. Use a value of 0 to hide initializers completely. 
+# The appearance of the initializer of individual variables and defines in the 
+# documentation can be controlled using \showinitializer or \hideinitializer 
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated 
+# at the bottom of the documentation of classes and structs. If set to YES the 
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES        = YES
+
+# If the sources in your project are distributed over multiple directories 
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy 
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES       = NO
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. 
+# This will remove the Files entry from the Quick Index and from the 
+# Folder Tree View (if specified). The default is YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the 
+# Namespaces page.  This will remove the Namespaces entry from the Quick Index 
+# and from the Folder Tree View (if specified). The default is YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that 
+# doxygen should invoke to get the current version for each file (typically from 
+# the version control system). Doxygen will invoke the program by executing (via 
+# popen()) the command <command> <input-file>, where <command> is the value of 
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file 
+# provided by doxygen. Whatever the program writes to standard output 
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER    = 
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed 
+# by doxygen. The layout file controls the global structure of the generated 
+# output files in an output format independent way. The create the layout file 
+# that represents doxygen's defaults, run doxygen with the -l option. 
+# You can optionally specify a file name after the option, if omitted 
+# DoxygenLayout.xml will be used as the name of the layout file.
+
+LAYOUT_FILE            = 
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated 
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are 
+# generated by doxygen. Possible values are YES and NO. If left blank 
+# NO is used.
+
+WARNINGS               = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings 
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will 
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for 
+# potential errors in the documentation, such as not documenting some 
+# parameters in a documented function, or documenting parameters that 
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR      = YES
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for 
+# functions that are documented, but have no documentation for their parameters 
+# or return value. If set to NO (the default) doxygen will only warn about 
+# wrong or incomplete parameter documentation, but not about the absence of 
+# documentation.
+
+WARN_NO_PARAMDOC       = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that 
+# doxygen can produce. The string should contain the $file, $line, and $text 
+# tags, which will be replaced by the file and line number from which the 
+# warning originated and the warning text. Optionally the format may contain 
+# $version, which will be replaced by the version of the file (if it could 
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning 
+# and error messages should be written. If left blank the output is written 
+# to stderr.
+
+WARN_LOGFILE           = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain 
+# documented source files. You may enter file names like "myfile.cpp" or 
+# directories like "/usr/src/myproject". Separate the files or directories 
+# with spaces.
+
+INPUT                  = /home/jacob/Desktop/gnu-octave/gui/src
+
+# This tag can be used to specify the character encoding of the source files 
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is 
+# also the default input encoding. Doxygen uses libiconv (or the iconv built 
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for 
+# the list of possible encodings.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the 
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 
+# and *.h) to filter out the source-files in the directories. If left 
+# blank the following patterns are tested: 
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx 
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90
+
+FILE_PATTERNS          = *.c \
+                         *.cc \
+                         *.cxx \
+                         *.cpp \
+                         *.c++ \
+                         *.d \
+                         *.java \
+                         *.ii \
+                         *.ixx \
+                         *.ipp \
+                         *.i++ \
+                         *.inl \
+                         *.h \
+                         *.hh \
+                         *.hxx \
+                         *.hpp \
+                         *.h++ \
+                         *.idl \
+                         *.odl \
+                         *.cs \
+                         *.php \
+                         *.php3 \
+                         *.inc \
+                         *.m \
+                         *.mm \
+                         *.dox \
+                         *.py \
+                         *.f90 \
+                         *.f \
+                         *.vhd \
+                         *.vhdl
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories 
+# should be searched for input files as well. Possible values are YES and NO. 
+# If left blank NO is used.
+
+RECURSIVE              = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should 
+# excluded from the INPUT source files. This way you can easily exclude a 
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE                = 
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or 
+# directories that are symbolic links (a Unix filesystem feature) are excluded 
+# from the input.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the 
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude 
+# certain files from those directories. Note that the wildcards are matched 
+# against the file with absolute path, so to exclude all test directories 
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       = 
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names 
+# (namespaces, classes, functions, etc.) that should be excluded from the 
+# output. The symbol name can be a fully qualified name, a word, or if the 
+# wildcard * is used, a substring. Examples: ANamespace, AClass, 
+# AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS        = 
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or 
+# directories that contain example code fragments that are included (see 
+# the \include command).
+
+EXAMPLE_PATH           = 
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the 
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 
+# and *.h) to filter out the source-files in the directories. If left 
+# blank all files are included.
+
+EXAMPLE_PATTERNS       = *
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be 
+# searched for input files to be used with the \include or \dontinclude 
+# commands irrespective of the value of the RECURSIVE tag. 
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or 
+# directories that contain image that are included in the documentation (see 
+# the \image command).
+
+IMAGE_PATH             = 
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should 
+# invoke to filter for each input file. Doxygen will invoke the filter program 
+# by executing (via popen()) the command <filter> <input-file>, where <filter> 
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an 
+# input file. Doxygen will then use the output that the filter program writes 
+# to standard output.  If FILTER_PATTERNS is specified, this tag will be 
+# ignored.
+
+INPUT_FILTER           = 
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern 
+# basis.  Doxygen will compare the file name with each pattern and apply the 
+# filter if there is a match.  The filters are a list of the form: 
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further 
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER 
+# is applied to all files.
+
+FILTER_PATTERNS        = 
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using 
+# INPUT_FILTER) will be used to filter the input files when producing source 
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES    = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will 
+# be generated. Documented entities will be cross-referenced with these sources. 
+# Note: To get rid of all source code in the generated output, make sure also 
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER         = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body 
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct 
+# doxygen to hide any special comment blocks from generated source code 
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES 
+# then for each documented function all documented 
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES 
+# then for each documented function all documented entities 
+# called/used by that function will be listed.
+
+REFERENCES_RELATION    = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) 
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from 
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will 
+# link to the source code.  Otherwise they will link to the documentation.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code 
+# will point to the HTML generated by the htags(1) tool instead of doxygen 
+# built-in source browser. The htags tool is part of GNU's global source 
+# tagging system (see http://www.gnu.org/software/global/global.html). You 
+# will need version 4.8.6 or higher.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen 
+# will generate a verbatim copy of the header file for each class for 
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS       = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index 
+# of all compounds will be generated. Enable this if the project 
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX     = YES
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then 
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns 
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all 
+# classes will be put under the same header in the alphabetical index. 
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that 
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX          = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will 
+# generate HTML output.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for 
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank 
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for 
+# each generated HTML page. If it is left blank doxygen will generate a 
+# standard header.
+
+HTML_HEADER            = 
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for 
+# each generated HTML page. If it is left blank doxygen will generate a 
+# standard footer.
+
+HTML_FOOTER            = 
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading 
+# style sheet that is used by each HTML page. It can be used to 
+# fine-tune the look of the HTML output. If the tag is left blank doxygen 
+# will generate a default style sheet. Note that doxygen will try to copy 
+# the style sheet file to the HTML output directory, so don't put your own 
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET        = 
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. 
+# Doxygen will adjust the colors in the stylesheet and background images 
+# according to this color. Hue is specified as an angle on a colorwheel, 
+# see http://en.wikipedia.org/wiki/Hue for more information. 
+# For instance the value 0 represents red, 60 is yellow, 120 is green, 
+# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. 
+# The allowed range is 0 to 359.
+
+HTML_COLORSTYLE_HUE    = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of 
+# the colors in the HTML output. For a value of 0 the output will use 
+# grayscales only. A value of 255 will produce the most vivid colors.
+
+HTML_COLORSTYLE_SAT    = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to 
+# the luminance component of the colors in the HTML output. Values below 
+# 100 gradually make the output lighter, whereas values above 100 make 
+# the output darker. The value divided by 100 is the actual gamma applied, 
+# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, 
+# and 100 does not change the gamma.
+
+HTML_COLORSTYLE_GAMMA  = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML 
+# page will contain the date and time when the page was generated. Setting 
+# this to NO can help when comparing the output of multiple runs.
+
+HTML_TIMESTAMP         = YES
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, 
+# files or namespaces will be aligned in HTML using tables. If set to 
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS     = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML 
+# documentation will contain sections that can be hidden and shown after the 
+# page has loaded. For this to work a browser that supports 
+# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox 
+# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files 
+# will be generated that can be used as input for Apple's Xcode 3 
+# integrated development environment, introduced with OSX 10.5 (Leopard). 
+# To create a documentation set, doxygen will generate a Makefile in the 
+# HTML output directory. Running make will produce the docset in that 
+# directory and running "make install" will install the docset in 
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find 
+# it at startup. 
+# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html 
+# for more information.
+
+GENERATE_DOCSET        = NO
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the 
+# feed. A documentation feed provides an umbrella under which multiple 
+# documentation sets from a single provider (such as a company or product suite) 
+# can be grouped.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that 
+# should uniquely identify the documentation set bundle. This should be a 
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen 
+# will append .docset to the name.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify 
+# the documentation publisher. This should be a reverse domain-name style 
+# string, e.g. com.mycompany.MyDocSet.documentation.
+
+DOCSET_PUBLISHER_ID    = org.doxygen.Publisher
+
+# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher.
+
+DOCSET_PUBLISHER_NAME  = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files 
+# will be generated that can be used as input for tools like the 
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) 
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP      = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can 
+# be used to specify the file name of the resulting .chm file. You 
+# can add a path in front of the file if the result should not be 
+# written to the html output directory.
+
+CHM_FILE               = 
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can 
+# be used to specify the location (absolute path including file name) of 
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run 
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION           = 
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag 
+# controls if a separate .chi index file is generated (YES) or that 
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI           = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING 
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file 
+# content.
+
+CHM_INDEX_ENCODING     = 
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag 
+# controls whether a binary table of contents is generated (YES) or a 
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members 
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and 
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated 
+# that can be used as input for Qt's qhelpgenerator to generate a 
+# Qt Compressed Help (.qch) of the generated HTML documentation.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can 
+# be used to specify the file name of the resulting .qch file. 
+# The path specified is relative to the HTML output folder.
+
+QCH_FILE               = 
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating 
+# Qt Help Project output. For more information please see 
+# http://doc.trolltech.com/qthelpproject.html#namespace
+
+QHP_NAMESPACE          = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating 
+# Qt Help Project output. For more information please see 
+# http://doc.trolltech.com/qthelpproject.html#virtual-folders
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to 
+# add. For more information please see 
+# http://doc.trolltech.com/qthelpproject.html#custom-filters
+
+QHP_CUST_FILTER_NAME   = 
+
+# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the 
+# custom filter to add. For more information please see 
+# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters"> 
+# Qt Help Project / Custom Filters</a>.
+
+QHP_CUST_FILTER_ATTRS  = 
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this 
+# project's 
+# filter section matches. 
+# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes"> 
+# Qt Help Project / Filter Attributes</a>.
+
+QHP_SECT_FILTER_ATTRS  = 
+
+# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can 
+# be used to specify the location of Qt's qhelpgenerator. 
+# If non-empty doxygen will try to run qhelpgenerator on the generated 
+# .qhp file.
+
+QHG_LOCATION           = 
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files  
+# will be generated, which together with the HTML files, form an Eclipse help 
+# plugin. To install this plugin and make it available under the help contents 
+# menu in Eclipse, the contents of the directory containing the HTML and XML 
+# files needs to be copied into the plugins directory of eclipse. The name of 
+# the directory within the plugins directory should be the same as 
+# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before 
+# the help appears.
+
+GENERATE_ECLIPSEHELP   = NO
+
+# A unique identifier for the eclipse help plugin. When installing the plugin 
+# the directory name containing the HTML and XML files should also have 
+# this name.
+
+ECLIPSE_DOC_ID         = org.doxygen.Project
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at 
+# top of each HTML page. The value NO (the default) enables the index and 
+# the value YES disables it.
+
+DISABLE_INDEX          = NO
+
+# This tag can be used to set the number of enum values (range [1..20]) 
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index 
+# structure should be generated to display hierarchical information. 
+# If the tag value is set to YES, a side panel will be generated 
+# containing a tree-like index structure (just like the one that 
+# is generated for HTML Help). For this to work a browser that supports 
+# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). 
+# Windows users are probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW      = NO
+
+# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, 
+# and Class Hierarchy pages using a tree view instead of an ordered list.
+
+USE_INLINE_TREES       = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be 
+# used to set the initial width (in pixels) of the frame in which the tree 
+# is shown.
+
+TREEVIEW_WIDTH         = 250
+
+# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open 
+# links to external symbols imported via tag files in a separate window.
+
+EXT_LINKS_IN_WINDOW    = NO
+
+# Use this tag to change the font size of Latex formulas included 
+# as images in the HTML documentation. The default is 10. Note that 
+# when you change the font size after a successful doxygen run you need 
+# to manually remove any form_*.png images from the HTML output directory 
+# to force them to be regenerated.
+
+FORMULA_FONTSIZE       = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images 
+# generated for formulas are transparent PNGs. Transparent PNGs are 
+# not supported properly for IE 6.0, but are supported on all modern browsers. 
+# Note that when changing this option you need to delete any form_*.png files 
+# in the HTML output before the changes have effect.
+
+FORMULA_TRANSPARENT    = YES
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box 
+# for the HTML output. The underlying search engine uses javascript 
+# and DHTML and should work on any modern browser. Note that when using 
+# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets 
+# (GENERATE_DOCSET) there is already a search function so this one should 
+# typically be disabled. For large projects the javascript based search engine 
+# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution.
+
+SEARCHENGINE           = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be 
+# implemented using a PHP enabled web server instead of at the web client 
+# using Javascript. Doxygen will generate the search PHP script and index 
+# file to put on the web server. The advantage of the server 
+# based approach is that it scales better to large projects and allows 
+# full text search. The disadvances is that it is more difficult to setup 
+# and does not have live searching capabilities.
+
+SERVER_BASED_SEARCH    = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will 
+# generate Latex output.
+
+GENERATE_LATEX         = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be 
+# invoked. If left blank `latex' will be used as the default command name. 
+# Note that when enabling USE_PDFLATEX this option is only used for 
+# generating bitmaps for formulas in the HTML output, but not in the 
+# Makefile that is written to the output directory.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to 
+# generate index for LaTeX. If left blank `makeindex' will be used as the 
+# default command name.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact 
+# LaTeX documents. This may be useful for small projects and may help to 
+# save some trees in general.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used 
+# by the printer. Possible values are: a4, a4wide, letter, legal and 
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE             = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX 
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES         = 
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for 
+# the generated latex document. The header should contain everything until 
+# the first chapter. If it is left blank doxygen will generate a 
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER           = 
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated 
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will 
+# contain links (just like the HTML output) instead of page references 
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS         = YES
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of 
+# plain latex in the generated Makefile. Set this option to YES to get a 
+# higher quality PDF documentation.
+
+USE_PDFLATEX           = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. 
+# command to the generated LaTeX files. This will instruct LaTeX to keep 
+# running if errors occur, instead of asking the user for help. 
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE        = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not 
+# include the index chapters (such as File Index, Compound Index, etc.) 
+# in the output.
+
+LATEX_HIDE_INDICES     = NO
+
+# If LATEX_SOURCE_CODE is set to YES then doxygen will include 
+# source code with syntax highlighting in the LaTeX output. 
+# Note that which sources are shown also depends on other settings 
+# such as SOURCE_BROWSER.
+
+LATEX_SOURCE_CODE      = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output 
+# The RTF output is optimized for Word 97 and may not look very pretty with 
+# other RTF readers or editors.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact 
+# RTF documents. This may be useful for small projects and may help to 
+# save some trees in general.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated 
+# will contain hyperlink fields. The RTF file will 
+# contain links (just like the HTML output) instead of page references. 
+# This makes the output suitable for online browsing using WORD or other 
+# programs which support those fields. 
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's 
+# config file, i.e. a series of assignments. You only have to provide 
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE    = 
+
+# Set optional variables used in the generation of an rtf document. 
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE    = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will 
+# generate man pages
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to 
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION          = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output, 
+# then it will generate one additional man file for each entity 
+# documented in the real man page(s). These additional files 
+# only source the real man page, but without them the man command 
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will 
+# generate an XML file that captures the structure of 
+# the code including all documentation.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT             = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema, 
+# which can be used by a validating XML parser to check the 
+# syntax of the XML files.
+
+XML_SCHEMA             = 
+
+# The XML_DTD tag can be used to specify an XML DTD, 
+# which can be used by a validating XML parser to check the 
+# syntax of the XML files.
+
+XML_DTD                = 
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will 
+# dump the program listings (including syntax highlighting 
+# and cross-referencing information) to the XML output. Note that 
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will 
+# generate an AutoGen Definitions (see autogen.sf.net) file 
+# that captures the structure of the code including all 
+# documentation. Note that this feature is still experimental 
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will 
+# generate a Perl module file that captures the structure of 
+# the code including all documentation. Note that this 
+# feature is still experimental and incomplete at the 
+# moment.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate 
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able 
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be 
+# nicely formatted so it can be parsed by a human reader.  This is useful 
+# if you want to understand what is going on.  On the other hand, if this 
+# tag is set to NO the size of the Perl module output will be much smaller 
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file 
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. 
+# This is useful so different doxyrules.make files included by the same 
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX = 
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will 
+# evaluate all C-preprocessor directives found in the sources and include 
+# files.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro 
+# names in the source code. If set to NO (the default) only conditional 
+# compilation will be performed. Macro expansion can be done in a controlled 
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION        = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES 
+# then the macro expansion is limited to the macros specified with the 
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files 
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that 
+# contain include files that are not input files but should be processed by 
+# the preprocessor.
+
+INCLUDE_PATH           = 
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard 
+# patterns (like *.h and *.hpp) to filter out the header-files in the 
+# directories. If left blank, the patterns specified with FILE_PATTERNS will 
+# be used.
+
+INCLUDE_FILE_PATTERNS  = 
+
+# The PREDEFINED tag can be used to specify one or more macro names that 
+# are defined before the preprocessor is started (similar to the -D option of 
+# gcc). The argument of the tag is a list of macros of the form: name 
+# or name=definition (no spaces). If the definition and the = are 
+# omitted =1 is assumed. To prevent a macro definition from being 
+# undefined via #undef or recursively expanded use the := operator 
+# instead of the = operator.
+
+PREDEFINED             = 
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then 
+# this tag can be used to specify a list of macro names that should be expanded. 
+# The macro definition that is found in the sources will be used. 
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED      = 
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then 
+# doxygen's preprocessor will remove all function-like macros that are alone 
+# on a line, have an all uppercase name, and do not end with a semicolon. Such 
+# function macros are typically used for boiler-plate code, and will confuse 
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles. 
+# Optionally an initial location of the external documentation 
+# can be added for each tagfile. The format of a tag file without 
+# this location is as follows: 
+#   TAGFILES = file1 file2 ... 
+# Adding location for the tag files is done as follows: 
+#   TAGFILES = file1=loc1 "file2 = loc2" ... 
+# where "loc1" and "loc2" can be relative or absolute paths or 
+# URLs. If a location is present for each tag, the installdox tool 
+# does not have to be run to correct the links. 
+# Note that each tag file must have a unique name 
+# (where the name does NOT include the path) 
+# If a tag file is not located in the directory in which doxygen 
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES               = 
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create 
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE       = 
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed 
+# in the class index. If set to NO only the inherited external classes 
+# will be listed.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed 
+# in the modules index. If set to NO, only the current project's groups will 
+# be listed.
+
+EXTERNAL_GROUPS        = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script 
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will 
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base 
+# or super classes. Setting the tag to NO turns the diagrams off. Note that 
+# this option is superseded by the HAVE_DOT option below. This is only a 
+# fallback. It is recommended to install and use dot, since it yields more 
+# powerful graphs.
+
+CLASS_DIAGRAMS         = NO
+
+# You can define message sequence charts within doxygen comments using the \msc 
+# command. Doxygen will then run the mscgen tool (see 
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the 
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where 
+# the mscgen tool resides. If left empty the tool is assumed to be found in the 
+# default search path.
+
+MSCGEN_PATH            = 
+
+# If set to YES, the inheritance and collaboration graphs will hide 
+# inheritance and usage relations if the target is undocumented 
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is 
+# available from the path. This tool is part of Graphviz, a graph visualization 
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section 
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT               = YES
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is 
+# allowed to run in parallel. When set to 0 (the default) doxygen will 
+# base this on the number of processors available in the system. You can set it 
+# explicitly to a value larger than 0 to get control over the balance 
+# between CPU load and processing speed.
+
+DOT_NUM_THREADS        = 0
+
+# By default doxygen will write a font called FreeSans.ttf to the output 
+# directory and reference it in all dot files that doxygen generates. This 
+# font does not include all possible unicode characters however, so when you need 
+# these (or just want a differently looking font) you can specify the font name 
+# using DOT_FONTNAME. You need need to make sure dot is able to find the font, 
+# which can be done by putting it in a standard location or by setting the 
+# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory 
+# containing the font.
+
+DOT_FONTNAME           = FreeSans.ttf
+
+# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. 
+# The default size is 10pt.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the output directory to look for the 
+# FreeSans.ttf font (which doxygen will put there itself). If you specify a 
+# different font using DOT_FONTNAME you can set the path where dot 
+# can find it using this tag.
+
+DOT_FONTPATH           = 
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for each documented class showing the direct and 
+# indirect inheritance relations. Setting this tag to YES will force the 
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for each documented class showing the direct and 
+# indirect implementation dependencies (inheritance, containment, and 
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and 
+# collaboration diagrams in a style similar to the OMG's Unified Modeling 
+# Language.
+
+UML_LOOK               = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the 
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT 
+# tags are set to YES then doxygen will generate a graph for each documented 
+# file showing the direct and indirect include dependencies of the file with 
+# other documented files.
+
+INCLUDE_GRAPH          = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and 
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each 
+# documented header file showing the documented files that directly or 
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then 
+# doxygen will generate a call dependency graph for every global function 
+# or class method. Note that enabling this option will significantly increase 
+# the time of a run. So in most cases it will be better to enable call graphs 
+# for selected functions only using the \callgraph command.
+
+CALL_GRAPH             = YES
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then 
+# doxygen will generate a caller dependency graph for every global function 
+# or class method. Note that enabling this option will significantly increase 
+# the time of a run. So in most cases it will be better to enable caller 
+# graphs for selected functions only using the \callergraph command.
+
+CALLER_GRAPH           = YES
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen 
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES 
+# then doxygen will show the dependencies a directory has on other directories 
+# in a graphical way. The dependency relations are determined by the #include 
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images 
+# generated by dot. Possible values are png, jpg, or gif 
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT       = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be 
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH               = 
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that 
+# contain dot files that are included in the documentation (see the 
+# \dotfile command).
+
+DOTFILE_DIRS           = 
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of 
+# nodes that will be shown in the graph. If the number of nodes in a graph 
+# becomes larger than this value, doxygen will truncate the graph, which is 
+# visualized by representing a node as a red box. Note that doxygen if the 
+# number of direct children of the root node in a graph is already larger than 
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note 
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the 
+# graphs generated by dot. A depth value of 3 means that only nodes reachable 
+# from the root by following a path via at most 3 edges will be shown. Nodes 
+# that lay further from the root node will be omitted. Note that setting this 
+# option to 1 or 2 may greatly reduce the computation time needed for large 
+# code bases. Also note that the size of a graph can be further restricted by 
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent 
+# background. This is disabled by default, because dot on Windows does not 
+# seem to support this out of the box. Warning: Depending on the platform used, 
+# enabling this option may lead to badly anti-aliased labels on the edges of 
+# a graph (i.e. they become hard to read).
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output 
+# files in one run (i.e. multiple -o and -T options on the command line). This 
+# makes dot run faster, but since only newer versions of dot (>1.8.10) 
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS      = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will 
+# generate a legend page explaining the meaning of the various boxes and 
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will 
+# remove the intermediate dot files that are used to generate 
+# the various graphs.
+
+DOT_CLEANUP            = YES
new file mode 100644
--- /dev/null
+++ b/gui/languages/german
@@ -0,0 +1,175 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.0" language="de_DE">
+<context>
+    <name>FilesDockWidget</name>
+    <message>
+        <location filename="../src/FilesDockWidget.cpp" line="9"/>
+        <source>Current Folder</source>
+        <translation>Aktuelles Verzeichnis</translation>
+    </message>
+</context>
+<context>
+    <name>HistoryDockWidget</name>
+    <message>
+        <location filename="../src/HistoryDockWidget.cpp" line="41"/>
+        <source>Command History</source>
+        <translation>Befehlshistorie</translation>
+    </message>
+    <message>
+        <location filename="../src/HistoryDockWidget.cpp" line="60"/>
+        <source>History updated.</source>
+        <translation>Befehlshistorie aktualisiert.</translation>
+    </message>
+</context>
+<context>
+    <name>MainWindow</name>
+    <message>
+        <location filename="../src/MainWindow.cpp" line="42"/>
+        <source>Opening file.</source>
+        <translation>Öffne Datei.</translation>
+    </message>
+    <message>
+        <location filename="../src/MainWindow.cpp" line="68"/>
+        <source>Save Workspace</source>
+        <translation>Speichere Arbeitsumgebung</translation>
+    </message>
+    <message>
+        <location filename="../src/MainWindow.cpp" line="76"/>
+        <source>Load Workspace</source>
+        <translation>Lade Arbeitsumgebung</translation>
+    </message>
+    <message>
+        <location filename="../src/MainWindow.cpp" line="94"/>
+        <source>Saving data and shutting down.</source>
+        <translation>Speichere Daten und schließe.</translation>
+    </message>
+    <message>
+        <location filename="../src/MainWindow.cpp" line="119"/>
+        <source>Octave Toolbar</source>
+        <translation>Octave Werkzeugleiste</translation>
+    </message>
+    <message>
+        <location filename="../src/MainWindow.cpp" line="128"/>
+        <source>Command Window</source>
+        <translation>Konsolenfenster</translation>
+    </message>
+    <message>
+        <location filename="../src/MainWindow.cpp" line="129"/>
+        <source>File Editor</source>
+        <translation>Dateieditor</translation>
+    </message>
+    <message>
+        <location filename="../src/MainWindow.cpp" line="130"/>
+        <source>Documentation</source>
+        <translation>Dokumentation</translation>
+    </message>
+    <message>
+        <location filename="../src/MainWindow.cpp" line="131"/>
+        <source>Service</source>
+        <translation>Service</translation>
+    </message>
+    <message>
+        <location filename="../src/MainWindow.cpp" line="179"/>
+        <source>Established link to Octave.</source>
+        <translation>Verbindung zu Octave hergestellt.</translation>
+    </message>
+</context>
+<context>
+    <name>NumberBar</name>
+    <message>
+        <location filename="../src/NumberedCodeEdit.cpp" line="189"/>
+        <source>Stop Here</source>
+        <translation>Stoppe hier</translation>
+    </message>
+    <message>
+        <location filename="../src/NumberedCodeEdit.cpp" line="192"/>
+        <source>Current Line</source>
+        <translation>Aktuelle Zeile</translation>
+    </message>
+    <message>
+        <location filename="../src/NumberedCodeEdit.cpp" line="195"/>
+        <source>Error Line</source>
+        <translation>Fehlerzeile</translation>
+    </message>
+</context>
+<context>
+    <name>NumberedCodeEdit</name>
+    <message>
+        <location filename="../src/NumberedCodeEdit.cpp" line="387"/>
+        <source>This file name is not valid.</source>
+        <translation>Dieser Dateiname ist nicht gültig.</translation>
+    </message>
+    <message>
+        <location filename="../src/NumberedCodeEdit.cpp" line="388"/>
+        <source>Octave doesn&apos;t understand this file name:
+</source>
+        <translation>Octave versteht diesen Dateityp nicht:</translation>
+    </message>
+    <message>
+        <location filename="../src/NumberedCodeEdit.cpp" line="388"/>
+        <source>
+Please, change it.
+ Do you want to save your changes?</source>
+        <translation>Bitte ändern Sie dies. Möchten Sie Ihre Änderungen sichern?</translation>
+    </message>
+</context>
+<context>
+    <name>VariablesDockWidget</name>
+    <message>
+        <location filename="../src/VariablesDockWidget.cpp" line="15"/>
+        <source>Name</source>
+        <translation>Bezeichner</translation>
+    </message>
+    <message>
+        <location filename="../src/VariablesDockWidget.cpp" line="15"/>
+        <source>Type</source>
+        <translation>Typ</translation>
+    </message>
+    <message>
+        <location filename="../src/VariablesDockWidget.cpp" line="15"/>
+        <source>Value</source>
+        <translation>Wert</translation>
+    </message>
+    <message>
+        <location filename="../src/VariablesDockWidget.cpp" line="21"/>
+        <source>Workspace</source>
+        <translation>Arbeitsumgebung</translation>
+    </message>
+    <message>
+        <location filename="../src/VariablesDockWidget.cpp" line="29"/>
+        <source>Save</source>
+        <translation>Sichern</translation>
+    </message>
+    <message>
+        <location filename="../src/VariablesDockWidget.cpp" line="30"/>
+        <source>Load</source>
+        <translation>Laden</translation>
+    </message>
+    <message>
+        <location filename="../src/VariablesDockWidget.cpp" line="31"/>
+        <source>Clear</source>
+        <translation>Löschen</translation>
+    </message>
+    <message>
+        <location filename="../src/VariablesDockWidget.cpp" line="46"/>
+        <source>Local</source>
+        <translation>Lokal</translation>
+    </message>
+    <message>
+        <location filename="../src/VariablesDockWidget.cpp" line="50"/>
+        <source>Global</source>
+        <translation>Global</translation>
+    </message>
+    <message>
+        <location filename="../src/VariablesDockWidget.cpp" line="54"/>
+        <source>Persistent</source>
+        <translation>Persistent</translation>
+    </message>
+    <message>
+        <location filename="../src/VariablesDockWidget.cpp" line="58"/>
+        <source>Hidden</source>
+        <translation>Versteckt</translation>
+    </message>
+</context>
+</TS>
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..13cd427ba4fa69ba638a54f79dbb25ff3e02654c
GIT binary patch
literal 2753
zc$}41U1(fI6h52%Np_oTYAX^n#1Vu_4EqqMXpn~dHfq`gHY6%Ryt{Xjz3$za<=)v1
z2|g);2tJA6gFg5qh-fJ&Rk2oR!79ZE(Kq!$L8wYauoMyWo4GglZqnP0vh1DNxpThr
zo$t&!vk#xMhrYP>`m0y&8UFO?H$VAqnuva<>~TfZdxf$K$BFtTDErzaj29?-fn)rO
z9=-oLydR?S(o00y8&rPcS*)jN{rUHa@?)vX=UyPnY@~iWf&J<Ap5j&P@A)kK#+Ppq
zrS49jPnU>tuVj9F9Cp3s%(b`AV|+PtBYy<@#<FLRevf@;a`%1!|Cy_~sh_{W_)eer
zr3d^dKl;$0cv|_(Ux8O<yfFCrMfl%2H2%?tc)i~L;6Lxe@5ciRUr&PHv4Km!7P0<b
zas34L_qfGB+^2y5%pjc=*f-<=>`WRvMrn%bq^L!lTzokB#Ap?xM>}{rRHYgTjDDXc
zlEb$+)ABqn6q}c>&AnbM4bD3*_h)6bzUJ7QT%|Pj2u%ZF1K%2ueLR5zUlQ03@d$5l
zMm8Fju-Ss+E9q@(z}v$4KFEpgkf3gb;aGUD-#I1}MWx8y;Sid&nzp65UFza*gdPL7
z0FE@`2;*BApTO;qBn)BA5w_gYh=o&@BZ8j>>Q0&kNFCG~210?N0zJS-FavPkYCu{`
zIZ`B{OozFtz*3M6G(npPdj~T{OURbSZ5t_SX6L5KsS5MkDa2iKzOpK=<JY*&Tu0QI
zl5DA}tTrzt`Mv`YSO!UpYU62ykMIuZL%`;22SO&<-$#qEw+*)`69YFGzR^VUtOW7I
zvMx#sno6(kH?1m90v+8K^qL8}ZVqn?pssOZ1c+gSAlZtPZpBLEIz-<h)f-@=LF2e%
z^#+!jTsUHrZ6NAIy~e3b&8UVnt^W~uSrhCU`9vc8E>(ef%N!8~H&s(FI&DAT8wW80
zH#!Csg2nXt^=mDq%!=F+iBT2dRy%7O$FZorW$v||WU9kAbs0ua8tQHbLjP`GS#*Sf
z$)9dDD%_j4yzu<ZhlL+^r%wCAoaagJ*4AZnUYkZVW?DyQ3Fpg7HrWFAl8oCZJe@FQ
zOn)-EY7$!Ia@cunGx}7*{1ja`n(t;}ch4hO3-WX^!U#$@*ynd-Q_y5Y?t#Lx%PpUe
zv1-i{o18hSRA94`ZOazhvY;7C*Vjh|3tqU%pVW~Y4kF?9jI_BfP7~1LzOrc>mqDM<
zwBv9BVsQm1+J=J6+zCO56A{hPu&`{&eQ`{&mcadhCWC{eYL0J8g$b*{CknTwHjB@$
zYj2Nhfmy@Q4Jx{m1cQcun+E4#7N79pl|7Cbeh8^p+j5<t^Cy!iLZRzn;qZ<Qot;4*
zOvgC7YIzRY=S|mMKb-^*iIT=06dC4Dy0T)qT`iA<%{@p%RhLX`zu?$57hUZOQG<;M
zXLJia&`MuSoous<vU&j7+s#$n`5&RPnlh&$_5t?GVX$F))^}oD%gZ=8xRTKhx}p?K
zX+<Ry``7)mt7VQ>^hu5_R<@hnE&9UCC1#mjwcJ*BqmlpE@bi0meIne8c+rze{R^V|
BTj2lz
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..919ba14e57ef0be670b475a5ce5614ac477a3e04
GIT binary patch
literal 12661
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
B{*(X!
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..8d014cbea8d1e5745038c7024a7e513067ef3a24
GIT binary patch
literal 2474
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
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..d05aed4e133cf47bae7ff4ead6405862073e0a33
GIT binary patch
literal 27810
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
Y*gBAQf`3K+-`8StQp%Dw5?@392fzQ;-v9sr
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..77b128c4d9f919d3e220d31f0ef679e4be12f08d
GIT binary patch
literal 43423
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
MGAhzlAk(1#0WcE#=Kufz
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..582581539bb1f74db61925f2b201ab75b490fea5
GIT binary patch
literal 15401
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
T-$=p#egex#DoRv+GYtG6SYdYL
new file mode 100644
--- /dev/null
+++ b/gui/src/BlockArray.cpp
@@ -0,0 +1,332 @@
+/*
+    This file is part of Konsole, an X terminal.
+    Copyright 2000 by Stephan Kulow <coolo@kde.org>
+
+    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"
+
+// System
+#include <assert.h>
+#include <sys/mman.h>
+#include <sys/param.h>
+#include <unistd.h>
+#include <stdio.h>
+
+#define KDE_fseek ::fseek
+#define KDE_lseek ::lseek
+
+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 = KDE_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) {
+        //kDebug(1211) << "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);
+        if (ftruncate(ion, length*blocksize) == -1)
+            perror("ftruncate");
+        size = newsize;
+
+        return true;
+    }
+}
+
+void moveBlock(FILE *fion, int cursor, int newpos, char *buffer2)
+{
+    int res = KDE_fseek(fion, cursor * blocksize, SEEK_SET);
+    if (res)
+        perror("fseek");
+    res = fread(buffer2, blocksize, 1, fion);
+    if (res != 1)
+        perror("fread");
+
+    res = KDE_fseek(fion, newpos * blocksize, SEEK_SET);
+    if (res)
+        perror("fseek");
+    res = fwrite(buffer2, blocksize, 1, fion);
+    if (res != 1)
+        perror("fwrite");
+}
+
+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 = KDE_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 = KDE_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/src/BlockArray.h
@@ -0,0 +1,115 @@
+/*
+    This file is part of Konsole, an X terminal.
+    Copyright 2000 by Stephan Kulow <coolo@kde.org>
+
+    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>
+
+#define BlockSize (1 << 12)
+#define ENTRIES   ((BlockSize - sizeof(size_t) ) / sizeof(unsigned char))
+
+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 transferred.
+    * 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/src/BrowserWidget.cpp
@@ -0,0 +1,90 @@
+/* Quint - A graphical user interface for Octave
+ * Copyright (C) 2011 Jacob Dawid
+ * jacob.dawid@googlemail.com
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "BrowserWidget.h"
+#include <QVBoxLayout>
+#include <QAction>
+#include <QStyle>
+#include <QApplication>
+
+BrowserDockWidget::BrowserDockWidget(QWidget *parent, BrowserWidget *browserWidget)
+    : QDockWidget(parent) {
+    m_browserWidget = browserWidget;
+    setWidget(m_browserWidget);
+}
+
+BrowserDockWidget::~BrowserDockWidget() {
+}
+
+BrowserWidget *BrowserDockWidget::browserWidget() {
+    return m_browserWidget;
+}
+
+BrowserWidget::BrowserWidget(QWidget *parent)
+    : QWidget(parent) {
+    construct();
+}
+
+void BrowserWidget::construct() {
+    QStyle *style = QApplication::style();
+    m_navigationToolBar = new QToolBar(this);
+    m_webView = new QWebView(this);
+    m_urlLineEdit = new QLineEdit(this);
+    m_statusBar = new QStatusBar(this);
+
+    QAction *backAction = new QAction(style->standardIcon(QStyle::SP_ArrowLeft),
+        "", m_navigationToolBar);
+    QAction *forwardAction = new QAction(style->standardIcon(QStyle::SP_ArrowRight),
+        "", m_navigationToolBar);
+
+    m_navigationToolBar->addAction(backAction);
+    m_navigationToolBar->addAction(forwardAction);
+    m_navigationToolBar->addWidget(m_urlLineEdit);
+
+    QVBoxLayout *layout = new QVBoxLayout();
+    layout->addWidget(m_navigationToolBar);
+    layout->addWidget(m_webView);
+    layout->addWidget(m_statusBar);
+    layout->setMargin(2);
+    setLayout(layout);
+
+    connect(backAction, SIGNAL(triggered()), m_webView, SLOT(back()));
+    connect(forwardAction, SIGNAL(triggered()), m_webView, SLOT(forward()));
+    connect(m_webView, SIGNAL(urlChanged(QUrl)), this, SLOT(setUrl(QUrl)));
+    connect(m_urlLineEdit, SIGNAL(returnPressed()), this, SLOT(jumpToWebsite()));
+    //connect(m_webView, SIGNAL(statusBarMessage(QString)), this, SLOT(showMessage(QString)));
+}
+
+void BrowserWidget::setUrl(QUrl url) {
+    m_urlLineEdit->setText(url.toString());
+}
+
+void BrowserWidget::jumpToWebsite() {
+    QString url = m_urlLineEdit->text();
+    if(!url.startsWith("http://"))
+        url = "http://" + url;
+    load(url);
+}
+
+void BrowserWidget::showStatusMessage(QString message) {
+    m_statusBar->showMessage(message, 1000);
+}
+
+void BrowserWidget::load(QUrl url) {
+    m_webView->load(url);
+}
new file mode 100644
--- /dev/null
+++ b/gui/src/BrowserWidget.h
@@ -0,0 +1,61 @@
+/* Quint - A graphical user interface for Octave
+ * Copyright (C) 2011 Jacob Dawid
+ * jacob.dawid@googlemail.com
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef BROWSERMDISUBWINDOW_H
+#define BROWSERMDISUBWINDOW_H
+
+#include <QWidget>
+#include <QToolBar>
+#include <QLineEdit>
+#include <QtWebKit/QWebView>
+#include <QStatusBar>
+#include <QDockWidget>
+
+class BrowserWidget;
+class BrowserDockWidget : public QDockWidget {
+public:
+    BrowserDockWidget(QWidget *parent, BrowserWidget *browserWidget);
+    ~BrowserDockWidget();
+
+    BrowserWidget *browserWidget();
+
+private:
+    BrowserWidget *m_browserWidget;
+};
+
+class BrowserWidget : public QWidget {
+    Q_OBJECT
+public:
+    BrowserWidget(QWidget *parent = 0);
+    void load(QUrl url);
+
+public slots:
+    void setUrl(QUrl url);
+    void jumpToWebsite();
+    void showStatusMessage(QString message);
+
+private:
+    void construct();
+
+    QLineEdit *m_urlLineEdit;
+    QToolBar *m_navigationToolBar;
+    QWebView *m_webView;
+    QStatusBar *m_statusBar;
+};
+
+#endif // BROWSERMDISUBWINDOW_H
new file mode 100644
--- /dev/null
+++ b/gui/src/Character.h
@@ -0,0 +1,220 @@
+/*
+    This file is part of Konsole, KDE's terminal.
+    
+    Copyright 2007-2008 by Robert Knight <robertknight@gmail.com>
+    Copyright 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
+
+    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"
+
+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. 
+   */
+  ColorEntry::FontWeight fontWeight(const ColorEntry* base) const;
+  
+  /** 
+   * returns true if the format (color, rendition flag) of the compared characters is equal
+   */
+  bool equalsFormat(const Character &other) 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::equalsFormat(const Character& other) const
+{
+  return 
+    backgroundColor==other.backgroundColor &&
+    foregroundColor==other.foregroundColor &&
+    rendition==other.rendition;
+}	
+
+inline ColorEntry::FontWeight Character::fontWeight(const ColorEntry* base) const
+{
+    if (backgroundColor._colorSpace == COLOR_SPACE_DEFAULT)
+        return base[backgroundColor._u+0+(backgroundColor._v?BASE_COLORS:0)].fontWeight;
+    else if (backgroundColor._colorSpace == COLOR_SPACE_SYSTEM)
+        return base[backgroundColor._u+2+(backgroundColor._v?BASE_COLORS:0)].fontWeight;
+    else
+        return ColorEntry::UseCurrentFormat;
+}
+
+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;
+};
+
+Q_DECLARE_TYPEINFO(Character, Q_MOVABLE_TYPE);
+
+#endif // CHARACTER_H
+
new file mode 100644
--- /dev/null
+++ b/gui/src/CharacterColor.h
@@ -0,0 +1,290 @@
+/*
+    This file is part of Konsole, KDE's terminal.
+    
+    Copyright 2007-2008 by Robert Knight <robertknight@gmail.com>
+    Copyright 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
+
+    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>
+
+/** 
+ * 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:
+  /** Specifies the weight to use when drawing text with this color. */
+  enum FontWeight 
+  {
+    /** Always draw text in this color with a bold weight. */
+    Bold,
+    /** Always draw text in this color with a normal weight. */
+    Normal,
+    /** 
+     * Use the current font weight set by the terminal application.  
+     * This is the default behavior.
+     */
+    UseCurrentFormat
+  };
+
+  /** 
+   * 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 weight Specifies the font weight to use when drawing text with this color. 
+   */
+  ColorEntry(QColor c, bool tr, FontWeight weight = UseCurrentFormat) 
+          : color(c), transparent(tr), fontWeight(weight) {}
+
+  /**
+   * Constructs a new color palette entry with an undefined color, and
+   * with the transparent and bold flags set to false.
+   */ 
+  ColorEntry() : transparent(false), fontWeight(UseCurrentFormat) {} 
+ 
+  /**
+   * 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; 
+       fontWeight = rhs.fontWeight; 
+  }
+
+  /** 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;
+  /**
+   * Specifies the font weight to use when drawing text with this color. 
+   * This is not applicable when the color is used to draw a character's background.
+   */
+  FontWeight fontWeight;        
+};
+
+
+// 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
+
+extern const ColorEntry base_color_table[TABLE_COLORS];
+
+/* 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 @p 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     a._colorSpace == b._colorSpace &&
+            a._u == b._u &&
+            a._v == b._v &&
+            a._w == b._w;
+}
+inline bool operator != (const CharacterColor& a, const CharacterColor& b)
+{
+    return !operator==(a,b);
+}
+
+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(((u/36)%6) ? (40*((u/36)%6)+55) : 0,
+                             ((u/ 6)%6) ? (40*((u/ 6)%6)+55) : 0,
+                             ((u/ 1)%6) ? (40*((u/ 1)%6)+55) : 0); 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/src/ColorTables.h
@@ -0,0 +1,56 @@
+#ifndef _COLOR_TABLE_H
+#define _COLOR_TABLE_H
+
+#include "CharacterColor.h"
+
+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/src/DefaultTranslatorText.h
@@ -0,0 +1,2 @@
+"keyboard \"Fallback Key Translator\"\n"
+"key Tab : \"\\t\" \0"
new file mode 100644
--- /dev/null
+++ b/gui/src/Emulation.cpp
@@ -0,0 +1,404 @@
+/*
+    Copyright 2007-2008 Robert Knight <robertknight@gmail.com> 
+    Copyright 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
+    Copyright 1996 by Matthias Ettrich <ettrich@kde.org>
+
+    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"
+
+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;
+}
+
+void Emulation::setScreen(int n)
+{
+  Screen *old = _currentScreen;
+  _currentScreen = _screen[n & 1];
+  if (_currentScreen != old) 
+  {
+     // tell all windows onto this emulation to switch to the newly active screen
+     foreach(ScreenWindow* window,_windows)
+         window->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() const
+{
+  return _screen[0]->getScroll();
+}
+
+void Emulation::setCodec(const QTextCodec * qtc)
+{
+  if (qtc)
+      _codec = qtc;
+  else
+     setCodec(LocaleCodec);
+
+  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);
+  if (!_keyTranslator)
+  {
+      _keyTranslator = KeyboardTranslatorManager::instance()->defaultTranslator();
+  }
+}
+
+QString Emulation::keyBindings() const
+{
+  return _keyTranslator->name();
+}
+
+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->tab();                       break;
+    case '\n'      : _currentScreen->newLine();                   break;
+    case '\r'      : _currentScreen->toStartOfLine();             break;
+    case 0x07      : emit stateSet(NOTIFYBELL);
+                     break;
+    default        : _currentScreen->displayCharacter(c);         break;
+  };
+}
+
+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
+    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
+}
+
+/*
+   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();
+        }
+    }
+}
+
+void Emulation::writeToStream( TerminalCharacterDecoder* _decoder , 
+                               int startLine ,
+                               int endLine) 
+{
+  _currentScreen->writeLinesToStream(_decoder,startLine,endLine);
+}
+
+int Emulation::lineCount() const
+{
+    // sum number of lines currently on _screen plus number of lines in history
+    return _currentScreen->getLines() + _currentScreen->getHistLines();
+}
+
+#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::eraseChar() const
+{
+  return '\b';
+}
+
+void Emulation::setImageSize(int lines, int columns)
+{
+  if ((lines < 1) || (columns < 1)) 
+    return;
+
+  QSize screenSize[2] = { QSize(_screen[0]->getColumns(),
+                                _screen[0]->getLines()),
+                          QSize(_screen[1]->getColumns(),
+                                _screen[1]->getLines()) };
+  QSize newSize(columns,lines);
+
+  if (newSize == screenSize[0] && newSize == screenSize[1])
+    return;    
+
+  _screen[0]->resizeImage(lines,columns);
+  _screen[1]->resizeImage(lines,columns);
+
+  emit imageSizeChanged(lines,columns);
+
+  bufferedUpdate();
+}
+
+QSize Emulation::imageSize() const
+{
+  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;
+
+
new file mode 100644
--- /dev/null
+++ b/gui/src/Emulation.h
@@ -0,0 +1,462 @@
+/*
+    This file is part of Konsole, an X terminal.
+    
+    Copyright 2007-2008 by Robert Knight <robertknight@gmail.com>
+    Copyright 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
+
+    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 <QtCore/QTextCodec>
+#include <QtCore/QTextStream>
+#include <QtCore/QTimer>
+
+
+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() const;
+
+  /**
+   * Returns the total number of lines, including those stored in the history.
+   */ 
+  int lineCount() const;
+
+  /** 
+   * 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() const;
+  /** 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 Index of first line to copy
+   * @param endLine Index of last line to copy
+   */
+  virtual void writeToStream(TerminalCharacterDecoder* decoder,int startLine,int endLine);
+  
+  /** Returns the codec used to decode incoming characters.  See setCodec() */
+  const QTextCodec* codec() const { 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() const
+  { Q_ASSERT(_codec); return _codec->mibEnum() == 106; }
+  
+
+  /** TODO Document me */
+  virtual char eraseChar() 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() const;
+
+  /** 
+   * 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
+   * @param 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);
+
+  /** 
+   * Emitted when a flow control key combination ( Ctrl+S or Ctrl+Q ) is pressed.
+   * @param suspendKeyPressed True if Ctrl+S was pressed to suspend output or Ctrl+Q to
+   * resume output.
+   */
+  void flowControlKeyPressed(bool suspendKeyPressed);
+
+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/src/FileEditorDockWidget.cpp
@@ -0,0 +1,146 @@
+/* Quint - A graphical user interface for Octave
+ * Copyright (C) 2011 Jacob Dawid
+ * jacob.dawid@googlemail.com
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "FileEditorDockWidget.h"
+#include <QVBoxLayout>
+#include <QApplication>
+#include <QFile>
+#include <QFileDialog>
+#include <QMessageBox>
+#include <QAction>
+
+FileEditorDockWidget::FileEditorDockWidget(QWidget *parent)
+    : QDockWidget(parent) {
+    construct();
+}
+
+void FileEditorDockWidget::loadFile(QString fileName) {
+    m_fileName = fileName;
+    setWindowTitle(fileName);
+    m_simpleEditor->load(fileName);
+}
+
+void FileEditorDockWidget::newFile() {
+    if(m_modified) {
+        int decision
+                = QMessageBox::question(this,
+                                        "Open New File",
+                                        "Do you want to save the current file?",
+                                        QMessageBox::Yes, QMessageBox::No);
+
+        if(decision == QMessageBox::Yes) {
+            saveFile();
+            if(m_modified) {
+                // If the user attempted to save the file, but it's still
+                // modified, then probably something went wrong, so we quit here.
+                return;
+            }
+        }
+    }
+
+    m_fileName = "<unnamed>";
+    setWindowTitle(m_fileName);
+    m_simpleEditor->setPlainText("");
+}
+
+void FileEditorDockWidget::saveFile() {
+    QString saveFileName = QFileDialog::getSaveFileName(this, "Save File", m_fileName);
+    if(saveFileName.isEmpty())
+        return;
+
+    QFile file(saveFileName);
+    file.open(QFile::WriteOnly);
+
+    if(file.write(m_simpleEditor->toPlainText().toLocal8Bit()) == -1) {
+        QMessageBox::warning(this,
+                             "Error Saving File",
+                             QString("The file could not be saved: %1.").arg(file.errorString()));
+    } else {
+        m_simpleEditor->document()->setModified(false);
+    }
+
+    file.close();
+}
+
+void FileEditorDockWidget::showToolTipNew() {
+    m_statusBar->showMessage("Create a new file.", 2000);
+}
+
+void FileEditorDockWidget::showToolTipSave() {
+    m_statusBar->showMessage("Save the file.", 2000);
+}
+
+void FileEditorDockWidget::showToolTipUndo() {
+    m_statusBar->showMessage("Revert previous changes.", 2000);
+}
+
+void FileEditorDockWidget::showToolTipRedo() {
+    m_statusBar->showMessage("Append previous changes.", 2000);
+}
+
+void FileEditorDockWidget::registerModified(bool modified) {
+    m_modified = modified;
+}
+
+void FileEditorDockWidget::construct() {
+    QStyle *style = QApplication::style();
+    setWidget(new QWidget());
+    m_toolBar = new QToolBar(this);
+    m_simpleEditor = new SimpleEditor(this);
+    m_statusBar = new QStatusBar(this);
+    m_numberedTextView = new NumberedCodeEdit(this, m_simpleEditor);
+
+    m_simpleEditor->setFont(QFont("Courier"));
+    m_simpleEditor->setLineWrapMode(QPlainTextEdit::NoWrap);
+
+    QAction *newAction = new QAction(style->standardIcon(QStyle::SP_FileIcon),
+        "", m_toolBar);
+    QAction *saveAction = new QAction(style->standardIcon(QStyle::SP_DriveHDIcon),
+        "", m_toolBar);
+    QAction *undoAction = new QAction(style->standardIcon(QStyle::SP_ArrowLeft),
+        "", m_toolBar);
+    QAction *redoAction = new QAction(style->standardIcon(QStyle::SP_ArrowRight),
+        "", m_toolBar);
+
+    m_toolBar->addAction(newAction);
+    m_toolBar->addAction(saveAction);
+    m_toolBar->addAction(undoAction);
+    m_toolBar->addAction(redoAction);
+
+    QVBoxLayout *layout = new QVBoxLayout();
+    layout->addWidget(m_toolBar);
+    layout->addWidget(m_numberedTextView);
+    layout->addWidget(m_statusBar);
+    layout->setMargin(2);
+    widget()->setLayout(layout);
+
+    connect(newAction, SIGNAL(triggered()), this, SLOT(newFile()));
+    connect(undoAction, SIGNAL(triggered()), m_simpleEditor, SLOT(undo()));
+    connect(redoAction, SIGNAL(triggered()), m_simpleEditor, SLOT(redo()));
+    connect(saveAction, SIGNAL(triggered()), this, SLOT(saveFile()));
+
+    connect(newAction, SIGNAL(hovered()), this, SLOT(showToolTipNew()));
+    connect(undoAction, SIGNAL(hovered()), this, SLOT(showToolTipUndo()));
+    connect(redoAction, SIGNAL(hovered()), this, SLOT(showToolTipRedo()));
+    connect(saveAction, SIGNAL(hovered()), this, SLOT(showToolTipSave()));
+
+    connect(m_simpleEditor, SIGNAL(modificationChanged(bool)), this, SLOT(registerModified(bool)));
+
+    m_fileName = "";
+    setWindowTitle(m_fileName);
+}
new file mode 100644
--- /dev/null
+++ b/gui/src/FileEditorDockWidget.h
@@ -0,0 +1,54 @@
+/* Quint - A graphical user interface for Octave
+ * Copyright (C) 2011 Jacob Dawid
+ * jacob.dawid@googlemail.com
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef FILEEDITORDOCKWIDGET_H
+#define FILEEDITORDOCKWIDGET_H
+
+#include <QDockWidget>
+#include <QToolBar>
+#include <QStatusBar>
+#include "SimpleEditor.h"
+#include "NumberedCodeEdit.h"
+
+class FileEditorDockWidget : public QDockWidget {
+    Q_OBJECT
+public:
+    FileEditorDockWidget(QWidget *parent = 0);
+    void loadFile(QString fileName);
+
+public slots:
+    void newFile();
+    void saveFile();
+
+    void showToolTipNew();
+    void showToolTipSave();
+    void showToolTipUndo();
+    void showToolTipRedo();
+
+    void registerModified(bool modified);
+private:
+    void construct();
+    QToolBar *m_toolBar;
+    SimpleEditor *m_simpleEditor;
+    NumberedCodeEdit *m_numberedTextView;
+    QStatusBar *m_statusBar;
+    QString m_fileName;
+    bool m_modified;
+};
+
+#endif // FILEEDITORDOCKWIDGET_H
new file mode 100644
--- /dev/null
+++ b/gui/src/FilesDockWidget.cpp
@@ -0,0 +1,98 @@
+#include "FilesDockWidget.h"
+
+#include <QApplication>
+#include <QFileInfo>
+
+FilesDockWidget::FilesDockWidget(QWidget *parent)
+  : QDockWidget(parent) {
+    setObjectName("FilesDockWidget");
+    setWindowTitle(tr("Current Folder"));
+    setWidget(new QWidget(this));
+
+    // Create a toolbar
+    m_navigationToolBar = new QToolBar("", widget());
+    m_navigationToolBar->setAllowedAreas(Qt::TopToolBarArea);
+    m_navigationToolBar->setMovable(false);
+    m_navigationToolBar->setIconSize(QSize (20,20));
+
+    // Add a button to the toolbar with the QT standard icon for up-directory
+    // TODO: Maybe change this to be an up-directory icon that is OS specific???
+    QStyle *style = QApplication::style();
+    m_directoryIcon = style->standardIcon(QStyle::SP_FileDialogToParent);
+    m_directoryUpAction = new QAction(m_directoryIcon, "", m_navigationToolBar);
+    m_currentDirectory = new QLineEdit(m_navigationToolBar);
+
+    m_navigationToolBar->addAction(m_directoryUpAction);
+    m_navigationToolBar->addWidget(m_currentDirectory);
+    connect(m_directoryUpAction, SIGNAL(triggered()), this, SLOT(onUpDirectory()));
+
+    // TODO: Add other buttons for creating directories
+
+    // Create the QFileSystemModel starting in the home directory
+    QString homePath = QDir::homePath();
+    // TODO: This should occur after Octave has been initialized and the startup directory of Octave is established
+
+    m_fileSystemModel = new QFileSystemModel(this);
+    m_fileSystemModel->setFilter(QDir::NoDotAndDotDot | QDir::AllEntries);
+    QModelIndex rootPathIndex = m_fileSystemModel->setRootPath(homePath);
+
+    // Attach the model to the QTreeView and set the root index
+    m_fileTreeView = new QTreeView(widget());
+    m_fileTreeView->setModel(m_fileSystemModel);
+    m_fileTreeView->setRootIndex(rootPathIndex);
+    m_fileTreeView->setSortingEnabled(true);
+    m_fileTreeView->setAlternatingRowColors(true);
+    m_fileTreeView->setAnimated(true);
+    setCurrentDirectory(m_fileSystemModel->fileInfo(rootPathIndex).absoluteFilePath());
+
+    connect(m_fileTreeView, SIGNAL(doubleClicked(const QModelIndex &)), this, SLOT(itemDoubleClicked(const QModelIndex &)));
+
+    // Layout the widgets vertically with the toolbar on top
+    QVBoxLayout *layout = new QVBoxLayout();
+    layout->setSpacing(0);
+    layout->addWidget(m_navigationToolBar);
+    layout->addWidget(m_fileTreeView);
+    widget()->setLayout(layout);
+    // TODO: Add right-click contextual menus for copying, pasting, deleting files (and others)
+
+    connect(m_currentDirectory, SIGNAL(returnPressed()), this, SLOT(currentDirectoryEntered()));
+    //m_currentDirectory->setEnabled(false);
+}
+
+void FilesDockWidget::itemDoubleClicked(const QModelIndex &index)
+{
+    QFileInfo fileInfo = m_fileSystemModel->fileInfo(index);
+    if (fileInfo.isDir()) {
+        m_fileSystemModel->setRootPath(fileInfo.absolutePath());
+        m_fileTreeView->setRootIndex(index);
+        setCurrentDirectory(m_fileSystemModel->fileInfo(index).absoluteFilePath());
+    } else {
+        QFileInfo fileInfo = m_fileSystemModel->fileInfo(index);
+        emit openFile(fileInfo.filePath());
+    }
+}
+
+void FilesDockWidget::setCurrentDirectory(QString currentDirectory) {
+    m_currentDirectory->setText(currentDirectory);
+}
+
+void FilesDockWidget::onUpDirectory(void) {
+    // Move up an inm_fileTreeView->setRootIndex(m_fileSystemModel->index(dir.absolutePath()));dex node
+    QDir dir = QDir(m_fileSystemModel->filePath(m_fileTreeView->rootIndex()));
+    dir.cdUp();
+    m_fileSystemModel->setRootPath(dir.absolutePath());
+    m_fileTreeView->setRootIndex(m_fileSystemModel->index(dir.absolutePath()));
+    setCurrentDirectory(dir.absolutePath());
+}
+
+void FilesDockWidget::currentDirectoryEntered() {
+    QFileInfo fileInfo(m_currentDirectory->text());
+    if (fileInfo.isDir()) {
+        m_fileTreeView->setRootIndex(m_fileSystemModel->index(fileInfo.absolutePath()));
+        m_fileSystemModel->setRootPath(fileInfo.absolutePath());
+        setCurrentDirectory(fileInfo.absoluteFilePath());
+    } else {
+        if(QFile::exists(fileInfo.absoluteFilePath()))
+            emit openFile(fileInfo.absoluteFilePath());
+    }
+}
new file mode 100644
--- /dev/null
+++ b/gui/src/FilesDockWidget.h
@@ -0,0 +1,86 @@
+/* Quint - A graphical user interface for Octave
+ * Copyright (C) 2011 John P. Swensen, Jacob Dawid
+ * jacob.dawid@googlemail.com
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef FILESDOCKWIDGET_H
+#define FILESDOCKWIDGET_H
+
+#include <QListView>
+#include <QDate>
+#include <QObject>
+#include <QWidget>
+#include <QListWidget>
+#include <QFileSystemModel>
+#include <QToolBar>
+#include <QToolButton>
+#include <QVBoxLayout>
+#include <QAction>
+#include <QTreeView>
+
+#include <vector>
+#include <string>
+
+#undef PACKAGE_BUGREPORT
+#undef PACKAGE_NAME
+#undef PACKAGE_STRING
+#undef PACKAGE_TARNAME
+#undef PACKAGE_VERSION
+#include "octave/config.h"
+#include "octave/octave.h"
+#include "octave/str-vec.h"
+#include "octave/cmd-hist.h"
+#include <QDockWidget>
+#include <QLineEdit>
+
+class FilesDockWidget : public QDockWidget {
+    Q_OBJECT
+public :
+    FilesDockWidget(QWidget *parent = 0);
+public slots:
+    /** Slot for handling a change in directory via double click. */
+    void itemDoubleClicked(const QModelIndex &index);
+
+    /** Slot for handling the up-directory button in the toolbar. */
+    void onUpDirectory();
+
+    void setCurrentDirectory(QString currentDirectory);
+
+    void currentDirectoryEntered();
+
+signals:
+    void openFile(QString fileName);
+
+private:
+    // TODO: Add toolbar with buttons for navigating the path, creating dirs, etc
+
+    /** Toolbar for file and directory manipulation. */
+    QToolBar *m_navigationToolBar;
+
+    /** Variables for the up-directory action. */
+    QIcon m_directoryIcon;
+    QAction *m_directoryUpAction;
+    QToolButton *upDirectoryButton;
+
+    /** The file system model. */
+    QFileSystemModel *m_fileSystemModel;
+
+    /** The file system view. */
+    QTreeView *m_fileTreeView;
+    QLineEdit *m_currentDirectory;
+};
+
+#endif // FILESDOCKWIDGET_H
new file mode 100644
--- /dev/null
+++ b/gui/src/Filter.cpp
@@ -0,0 +1,534 @@
+/*
+    Copyright 2007-2008 by Robert Knight <robertknight@gmail.com>
+
+    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/QTextStream>
+#include <QtCore/QSharedData>
+#include <QtCore/QFile>
+
+// Konsole
+#include "TerminalCharacterDecoder.h"
+#include "konsole_wcwidth.h"
+#include "konsole_export.h"
+
+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)
+{
+    if (empty())
+        return;
+
+    // reset all filters and hotspots
+    reset();
+
+    PlainTextDecoder decoder;
+    decoder.setTrailingWhitespace(false);
+    
+    // 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();
+}
+
+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++)
+    {
+        int nextLine = 0;
+
+        if ( i == _linePositions->count()-1 )
+            nextLine = _buffer->length() + 1;
+        else
+            nextLine = _linePositions->value(i+1);
+
+        if ( _linePositions->value(i) <= position && position < nextLine ) 
+        {
+            startLine = i;
+            startColumn = string_width(buffer()->mid(_linePositions->value(i),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;
+
+            getLineColumn(pos,startLine,startColumn);
+            getLineColumn(pos + _searchText.matchedLength(),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
+            if ( _searchText.matchedLength() == 0 )
+                pos = -1;
+        }
+    }    
+}
+
+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" )
+    {
+        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(i18n("Open Link"));
+        copyAction->setText(i18n("Copy Link Address"));
+    }
+    else if ( kind == Email )
+    {
+        openAction->setText(i18n("Send Email To..."));
+        copyAction->setText(i18n("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( QLatin1String("open-action" ));
+    copyAction->setObjectName( QLatin1String("copy-action" ));
+
+    QObject::connect( openAction , SIGNAL(triggered()) , _urlObject , SLOT(activated()) );
+    QObject::connect( copyAction , SIGNAL(triggered()) , _urlObject , SLOT(activated()) );
+
+    list << openAction;
+    list << copyAction;
+
+    return list; 
+}
+
new file mode 100644
--- /dev/null
+++ b/gui/src/Filter.h
@@ -0,0 +1,379 @@
+/*
+    Copyright 2007-2008 by Robert Knight <robertknight@gmail.com>
+
+    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"
+
+
+/**
+ * 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
+     * @param lineProperties The line properties to set for 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/src/History.cpp
@@ -0,0 +1,696 @@
+/*
+    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
+
+/*
+   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/src/History.h
@@ -0,0 +1,307 @@
+/*
+    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 HISTORY_H
+#define HISTORY_H
+
+// Qt
+#include <QtCore/QBitRef>
+#include <QtCore/QHash>
+#include <QtCore>
+
+// Konsole
+#include "BlockArray.h"
+#include "Character.h"
+
+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;
+};
+
+//////////////////////////////////////////////////////////////////////
+
+//////////////////////////////////////////////////////////////////////
+// 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;
+
+};
+
+
+
+//////////////////////////////////////////////////////////////////////
+// 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;
+};
+
+//////////////////////////////////////////////////////////////////////
+// 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;
+};
+
+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 // HISTORY_H
new file mode 100644
--- /dev/null
+++ b/gui/src/HistoryDockWidget.cpp
@@ -0,0 +1,61 @@
+/* Quint - A graphical user interface for Octave
+ * Copyright (C) 2011 Jacob Dawid
+ * jacob.dawid@googlemail.com
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "HistoryDockWidget.h"
+#include <QHBoxLayout>
+
+HistoryDockWidget::HistoryDockWidget(QWidget *parent)
+    : QDockWidget(parent) {
+    setObjectName("HistoryDockWidget");
+    construct();
+}
+
+void HistoryDockWidget::handleListViewItemDoubleClicked(QModelIndex modelIndex) {
+    QString command = m_historyListModel->data(modelIndex, 0).toString();
+    emit commandDoubleClicked(command);
+}
+
+void HistoryDockWidget::construct() {
+    m_historyListModel = new QStringListModel();
+    m_historyListView = new QListView(this);
+    m_historyListView->setModel(m_historyListModel);
+    m_historyListView->setAlternatingRowColors(true);
+    m_historyListView->setEditTriggers(QAbstractItemView::NoEditTriggers);
+    QHBoxLayout *layout = new QHBoxLayout();
+
+    setWindowTitle(tr("Command History"));
+    setWidget(new QWidget());
+
+    layout->addWidget(m_historyListView);
+    layout->setMargin(2);
+
+    widget()->setLayout(layout);
+    connect(m_historyListView, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(handleListViewItemDoubleClicked(QModelIndex)));
+}
+
+void HistoryDockWidget::updateHistory(string_vector historyEntries) {
+    QStringList stringList = m_historyListModel->stringList();
+    for(int i = 0; i < historyEntries.length(); i++) {
+        QString command(historyEntries[i].c_str());
+        if(!command.startsWith("#")) {
+            stringList.push_front(command);
+        }
+    }
+    m_historyListModel->setStringList(stringList);
+    emit information(tr("History updated."));
+}
new file mode 100644
--- /dev/null
+++ b/gui/src/HistoryDockWidget.h
@@ -0,0 +1,55 @@
+#ifndef HISTORYDOCKWIDGET_H
+#define HISTORYDOCKWIDGET_H
+
+#include <QDockWidget>
+#include <QListView>
+#include <QStringListModel>
+
+// Octave includes
+#undef PACKAGE_BUGREPORT
+#undef PACKAGE_NAME
+#undef PACKAGE_STRING
+#undef PACKAGE_TARNAME
+#undef PACKAGE_VERSION
+#undef PACKAGE_URL
+#include "octave/config.h"
+
+#include "octave/debug.h"
+#include "octave/octave.h"
+#include "octave/symtab.h"
+#include "octave/parse.h"
+#include "octave/unwind-prot.h"
+#include "octave/toplev.h"
+#include "octave/load-path.h"
+#include "octave/error.h"
+#include "octave/quit.h"
+#include "octave/variables.h"
+#include "octave/sighandlers.h"
+#include "octave/sysdep.h"
+#include "octave/str-vec.h"
+#include "octave/cmd-hist.h"
+#include "octave/cmd-edit.h"
+#include "octave/oct-env.h"
+#include "octave/symtab.h"
+#include "cmd-edit.h"
+
+class HistoryDockWidget : public QDockWidget {
+    Q_OBJECT
+public:
+    HistoryDockWidget(QWidget *parent = 0);
+    void updateHistory(string_vector historyEntries);
+
+signals:
+    void information(QString message);
+    void commandDoubleClicked(QString command);
+
+private slots:
+    void handleListViewItemDoubleClicked(QModelIndex modelIndex);
+
+private:
+    void construct();
+    QListView *m_historyListView;
+    QStringListModel *m_historyListModel;
+};
+
+#endif // HISTORYDOCKWIDGET_H
new file mode 100644
--- /dev/null
+++ b/gui/src/ImageViewerDockWidget.cpp
@@ -0,0 +1,23 @@
+#include "ImageViewerDockWidget.h"
+#include <QLabel>
+#include <QPixmap>
+#include <QScrollArea>
+
+ImageViewerDockWidget::ImageViewerDockWidget(QPixmap pixmap, QWidget *parent)
+    : QDockWidget(parent),
+      m_pixmap(pixmap) {
+    construct();
+}
+
+void ImageViewerDockWidget::construct() {
+    QLabel *label = new QLabel();
+    label->setBackgroundRole(QPalette::Base);
+    label->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
+    label->setScaledContents(true);
+    label->setPixmap(m_pixmap);
+
+    QScrollArea *scrollArea = new QScrollArea(this);
+    scrollArea->setBackgroundRole(QPalette::Dark);
+    scrollArea->setWidget(label);
+    setWidget(scrollArea);
+}
new file mode 100644
--- /dev/null
+++ b/gui/src/ImageViewerDockWidget.h
@@ -0,0 +1,15 @@
+#ifndef IMAGEVIEWERDOCKWIDGET_H
+#define IMAGEVIEWERDOCKWIDGET_H
+
+#include <QDockWidget>
+
+class ImageViewerDockWidget : public QDockWidget {
+public:
+    ImageViewerDockWidget(QPixmap pixmap, QWidget *parent = 0);
+
+private:
+    void construct();
+    QPixmap m_pixmap;
+};
+
+#endif // IMAGEVIEWERDOCKWIDGET_H
new file mode 100644
--- /dev/null
+++ b/gui/src/KeyboardTranslator.cpp
@@ -0,0 +1,970 @@
+/*
+    This source file is part of Konsole, a terminal emulator.
+
+    Copyright 2007-2008 by Robert Knight <robertknight@gmail.com>
+
+    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 <QtCore/QFile>
+#include <QtCore/QFileInfo>
+#include <QtCore/QTextStream>
+#include <QtGui/QKeySequence>
+#include <QtCore/QDir>
+#include <QtCore/QStringList>
+#include <QtCore/QDebug>
+#include <QtCore/QDataStream>
+
+const QByteArray KeyboardTranslatorManager::defaultTranslatorText(
+"keyboard \"Fallback Key Translator\"\n"
+"key Tab : \"\\t\""
+);
+
+KeyboardTranslatorManager::KeyboardTranslatorManager()
+    : _haveLoadedAll(false)
+{
+}
+KeyboardTranslatorManager::~KeyboardTranslatorManager()
+{
+    qDeleteAll(_translators);
+}
+QString KeyboardTranslatorManager::findTranslatorPath(const QString& name)
+{
+  return QString("../kb-layouts/" + name + ".keytab");
+  // return KGlobal::dirs()->findResource("data","konsole/"+name+".keytab");
+}
+void KeyboardTranslatorManager::findTranslators()
+{
+  //QStringList list = KGlobal::dirs()->findAllResources("data",
+  //                                                     "konsole/*.keytab",
+  //                                                     KStandardDirs::NoDuplicates);
+
+    QDir dir("../kb-layouts/");
+    QStringList filters;
+    filters << "*.keytab";
+    dir.setNameFilters(filters);
+    QStringList 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();
+
+    if ( _translators.contains(name) && _translators[name] != 0 )
+        return _translators[name];
+
+    KeyboardTranslator* translator = loadTranslator(name);
+
+    if ( translator != 0 )
+        _translators[name] = translator;
+    //else if ( !name.isEmpty() )
+    //  kWarning() << "Unable to load translator" << name;
+
+    return translator;
+}
+
+bool KeyboardTranslatorManager::saveTranslator(const KeyboardTranslator* translator)
+{
+  //const QString path = KGlobal::dirs()->saveLocation("data","konsole/")+translator->name()
+  //         +".keytab";
+  const QString path = ".keytab";
+
+    //kDebug() << "Saving translator to" << path;
+
+    QFile destination(path);
+    if (!destination.open(QIODevice::WriteOnly | QIODevice::Text))
+    {
+        //kWarning() << "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()
+{
+    // Try to find the default.keytab file if it exists, otherwise
+    // fall back to the hard-coded one
+    const KeyboardTranslator* translator = findTranslator("default");
+    if (!translator)
+    {
+        QBuffer textBuffer;
+        textBuffer.setData(defaultTranslatorText);
+        textBuffer.open(QIODevice::ReadOnly);
+        translator = loadTranslator(&textBuffer,"fallback");
+    }
+    return translator;
+}
+
+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() )
+   {
+        QList<Token> tokens = tokenize( QString(source->readLine()) );
+        if ( !tokens.isEmpty() && tokens.first().type == Token::TitleKeyword )
+            _description = QString(tokens[1].text.toLatin1().data());
+   }
+   // read first entry (if any)
+   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))
+                //  kWarning() << "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 isFirstLetter = i == 0;
+        bool isLastLetter = ( i == text.count()-1 );
+        endOfItem = true;
+        if ( ch.isLetterOrNumber() )
+        {
+            endOfItem = false;
+            buffer.append(ch);
+        } else if ( isFirstLetter )
+        {
+            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
+          //      kWarning() << "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" || item == "appcursorkeys" )
+        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" || item == "anymodifier" )
+        flag = KeyboardTranslator::AnyModifierState;
+    else if ( item == "appkeypad" )
+        flag = KeyboardTranslator::ApplicationKeypadState;
+    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 )
+        {
+            //kWarning() << "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();
+    QBuffer buffer(&array);
+    buffer.open(QIODevice::ReadOnly);
+    KeyboardTranslatorReader reader(&buffer);
+
+    KeyboardTranslator::Entry entry;
+    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;
+
+    // remove comments 
+    bool inQuotes = false;
+    int commentPos = -1;
+    for (int i=text.length()-1;i>=0;i--)
+    {
+        QChar ch = text[i];
+        if (ch == '\"')
+            inQuotes = !inQuotes;
+        else if (ch == '#' && !inQuotes)
+            commentPos = i;
+    }
+    if (commentPos != -1)
+        text.remove(commentPos,text.length());
+
+    text = text.simplified();
+   
+    // 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() ) 
+    {
+        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
+    {
+        //kWarning() << "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 testState) 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 )
+        testState |= AnyModifierState;
+
+    if ( (testState & _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;
+    bool wantAnyModifier = _state & KeyboardTranslator::AnyModifierState;
+    if ( _stateMask & KeyboardTranslator::AnyModifierState )
+    {
+        if ( wantAnyModifier != 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).toHex()); 
+        } 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];
+
+                    unsigned 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 += "AppCursorKeys";
+    else if ( state == KeyboardTranslator::AnyModifierState )
+        item += "AnyModifier";
+    else if ( state == KeyboardTranslator::ApplicationKeypadState )
+        item += "AppKeypad";
+}
+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();
+
+    insertModifier( result , Qt::ShiftModifier );
+    insertModifier( result , Qt::ControlModifier );
+    insertModifier( result , Qt::AltModifier );
+    insertModifier( result , Qt::MetaModifier );
+    insertModifier( result , Qt::KeypadModifier );
+
+    insertState( result , KeyboardTranslator::AlternateScreenState );
+    insertState( result , KeyboardTranslator::NewLineState );
+    insertState( result , KeyboardTranslator::AnsiState );
+    insertState( result , KeyboardTranslator::CursorKeysState );
+    insertState( result , KeyboardTranslator::AnyModifierState );
+    insertState( result , KeyboardTranslator::ApplicationKeypadState );
+
+    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.insert(keyCode,entry);
+}
+void KeyboardTranslator::replaceEntry(const Entry& existing , const Entry& replacement)
+{
+    if ( !existing.isNull() )
+        _entries.remove(existing.keyCode(),existing);
+    _entries.insert(replacement.keyCode(),replacement);
+}
+void KeyboardTranslator::removeEntry(const Entry& entry)
+{
+    _entries.remove(entry.keyCode(),entry);
+}
+KeyboardTranslator::Entry KeyboardTranslator::findEntry(int keyCode, Qt::KeyboardModifiers modifiers, States state) const
+{
+    foreach(const Entry& entry, _entries.values(keyCode))
+    {
+        if ( entry.matches(keyCode,modifiers,state) )
+            return entry;
+    }
+    return Entry(); // entry not found
+}
+void KeyboardTranslatorManager::addTranslator(KeyboardTranslator* translator)
+{
+    _translators.insert(translator->name(),translator);
+
+  //  if ( !saveTranslator(translator) )
+  //      kWarning() << "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
+    {
+        //kWarning() << "Failed to remove translator - " << path;
+        return false;
+    }
+}
+
+/**
+ * @internal
+ */
+typedef void (*KdeCleanUpFunction)();
+
+/**
+ * @internal
+ *
+ * Helper class for K_GLOBAL_STATIC to clean up the object on library unload or application
+ * shutdown.
+ */
+class KCleanUpGlobalStatic
+{
+    public:
+        KdeCleanUpFunction func;
+
+        inline ~KCleanUpGlobalStatic() { func(); }
+};
+
+
+
+#ifdef Q_CC_MSVC
+/**
+ * @internal
+ *
+ * MSVC seems to give anonymous structs the same name which fails at link time. So instead we name
+ * the struct and hope that by adding the line number to the name it's unique enough to never clash.
+ */
+# define K_GLOBAL_STATIC_STRUCT_NAME(NAME) _k_##NAME##__LINE__
+#else
+/**
+ * @internal
+ *
+ * Make the struct of the K_GLOBAL_STATIC anonymous.
+ */
+# define K_GLOBAL_STATIC_STRUCT_NAME(NAME)
+#endif
+
+
+
+#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)                                \
+{                                                                              \
+    inline bool isDestroyed() const                                            \
+    {                                                                          \
+        return _k_static_##NAME##_destroyed;                                   \
+    }                                                                          \
+    inline bool exists() const                                                 \
+    {                                                                          \
+        return _k_static_##NAME != 0;                                          \
+    }                                                                          \
+    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 KCleanUpGlobalStatic 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;
+
+#define K_GLOBAL_STATIC(TYPE, NAME) K_GLOBAL_STATIC_WITH_ARGS(TYPE, NAME, ())
+
+K_GLOBAL_STATIC( KeyboardTranslatorManager , theKeyboardTranslatorManager )
+KeyboardTranslatorManager* KeyboardTranslatorManager::instance()
+{
+    return theKeyboardTranslatorManager;
+}
new file mode 100644
--- /dev/null
+++ b/gui/src/KeyboardTranslator.h
@@ -0,0 +1,577 @@
+/*
+    This source file is part of Konsole, a terminal emulator.
+
+    Copyright 2007-2008 by Robert Knight <robertknight@gmail.com>
+
+    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>
+
+class QIODevice;
+class QTextStream;
+
+/** 
+ * 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,
+        /** Indicates that the numpad is in application mode. */
+        ApplicationKeypadState = 32
+    };
+    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:
+
+    QMultiHash<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 QByteArray 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(KeyboardTranslator::Entry)
+Q_DECLARE_METATYPE(const KeyboardTranslator*)
+
+#endif // KEYBOARDTRANSLATOR_H
+
new file mode 100644
--- /dev/null
+++ b/gui/src/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/src/MainWindow.cpp
@@ -0,0 +1,190 @@
+/* Quint - A graphical user interface for Octave
+ * Copyright (C) 2011 Jacob Dawid
+ * jacob.dawid@googlemail.com
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <QMenuBar>
+#include <QMenu>
+#include <QAction>
+#include <QSettings>
+#include <QDesktopServices>
+#include <QFileDialog>
+#include "MainWindow.h"
+#include "FileEditorDockWidget.h"
+#include "ImageViewerDockWidget.h"
+
+MainWindow::MainWindow(QWidget *parent)
+    : QMainWindow(parent),
+      m_isRunning(true) {
+    setObjectName("MainWindow");
+
+    QDesktopServices desktopServices;
+    m_settingsFile = desktopServices.storageLocation(QDesktopServices::HomeLocation) + "/.quint/settings.ini";
+    construct();
+    establishOctaveLink();
+}
+
+MainWindow::~MainWindow() {
+}
+
+void MainWindow::handleOpenFileRequest(QString fileName) {
+    reportStatusMessage(tr("Opening file."));
+    QPixmap pixmap;
+    if(pixmap.load(fileName)) {
+        ImageViewerDockWidget *imageViewerDockWidget = new ImageViewerDockWidget(pixmap, this);
+        imageViewerDockWidget->setWindowTitle(fileName);
+        addDockWidget(Qt::RightDockWidgetArea, imageViewerDockWidget);
+    } else {
+        FileEditorDockWidget *fileEditorDockWidget = new FileEditorDockWidget(this);
+        fileEditorDockWidget->loadFile(fileName);
+        addDockWidget(Qt::RightDockWidgetArea, fileEditorDockWidget);
+    }
+}
+
+void MainWindow::reportStatusMessage(QString statusMessage) {
+    m_statusBar->showMessage(statusMessage, 1000);
+}
+
+void MainWindow::handleSaveWorkspaceRequest() {
+    QDesktopServices desktopServices;
+    QString selectedFile = QFileDialog::getSaveFileName(this, tr("Save Workspace"),
+        desktopServices.storageLocation(QDesktopServices::HomeLocation) + "/.quint/workspace");
+    m_octaveTerminalDockWidget->octaveTerminal()->sendText(QString("save \'%1\'\n").arg(selectedFile));
+    m_octaveTerminalDockWidget->octaveTerminal()->setFocus();
+}
+
+void MainWindow::handleLoadWorkspaceRequest() {
+    QDesktopServices desktopServices;
+    QString selectedFile = QFileDialog::getOpenFileName(this, tr("Load Workspace"),
+        desktopServices.storageLocation(QDesktopServices::HomeLocation) + "/.quint/workspace");
+    m_octaveTerminalDockWidget->octaveTerminal()->sendText(QString("load \'%1\'\n").arg(selectedFile));
+    m_octaveTerminalDockWidget->octaveTerminal()->setFocus();
+}
+
+void MainWindow::handleClearWorkspaceRequest() {
+    m_octaveTerminalDockWidget->octaveTerminal()->sendText("clear\n");
+    m_octaveTerminalDockWidget->octaveTerminal()->setFocus();
+}
+
+void MainWindow::handleCommandDoubleClicked(QString command) {
+    m_octaveTerminalDockWidget->octaveTerminal()->sendText(command);
+    m_octaveTerminalDockWidget->octaveTerminal()->setFocus();
+}
+
+void MainWindow::closeEvent(QCloseEvent *closeEvent) {
+    m_isRunning = false;
+    reportStatusMessage(tr("Saving data and shutting down."));
+    writeSettings();
+
+    m_octaveCallbackThread->terminate();
+    m_octaveCallbackThread->wait();
+
+    m_octaveMainThread->terminate();
+    QMainWindow::closeEvent(closeEvent);
+}
+
+void MainWindow::readSettings() {
+    QSettings settings(m_settingsFile, QSettings::IniFormat);
+    restoreGeometry(settings.value("MainWindow/geometry").toByteArray());
+    restoreState(settings.value("MainWindow/windowState").toByteArray());
+}
+
+void MainWindow::writeSettings() {
+    QSettings settings(m_settingsFile, QSettings::IniFormat);
+    settings.setValue("MainWindow/geometry", saveGeometry());
+    settings.setValue("MainWindow/windowState", saveState());
+}
+
+void MainWindow::construct() {
+    setWindowTitle("Octave");
+    setWindowIcon(QIcon("../media/quint_icon_small.png"));
+    QStyle *style = QApplication::style();
+    resize(800, 600);
+
+    m_octaveTerminalDockWidget = new OctaveTerminalDockWidget(this, new OctaveTerminal(this));
+    m_variablesDockWidget = new VariablesDockWidget(this);
+    m_historyDockWidget = new HistoryDockWidget(this);
+    m_filesDockWidget = new FilesDockWidget(this);
+    m_browserDockWidget = new BrowserDockWidget(this, new BrowserWidget(this));
+    m_serviceDockWidget = new BrowserDockWidget(this, new BrowserWidget(this));
+
+    m_browserDockWidget->setObjectName("BrowserWidget");
+    m_browserDockWidget->setWindowTitle(tr("Documentation"));
+    m_serviceDockWidget->setObjectName("ServiceWidget");
+    m_serviceDockWidget->setWindowTitle(tr("Service"));
+
+    // This is needed, since a QMainWindow without a central widget is not supported.
+    setCentralWidget(new QWidget(this));
+    centralWidget()->setObjectName("CentralWidget");
+    centralWidget()->hide();
+
+    setDockOptions(QMainWindow::AllowTabbedDocks | QMainWindow::AllowNestedDocks | QMainWindow::AnimatedDocks);
+
+    addDockWidget(Qt::RightDockWidgetArea, m_octaveTerminalDockWidget);
+    addDockWidget(Qt::LeftDockWidgetArea, m_variablesDockWidget);
+    addDockWidget(Qt::LeftDockWidgetArea, m_historyDockWidget);
+    addDockWidget(Qt::LeftDockWidgetArea, m_filesDockWidget);
+    addDockWidget(Qt::LeftDockWidgetArea, m_browserDockWidget);
+    addDockWidget(Qt::LeftDockWidgetArea, m_serviceDockWidget);
+
+    // TODO: Add meaningfull toolbar items.
+    m_generalPurposeToolbar = new QToolBar(tr("Octave Toolbar"), this);
+    QAction *commandAction = new QAction(style->standardIcon(QStyle::SP_CommandLink),
+        "", m_generalPurposeToolbar);
+    QAction *computerAction = new QAction(style->standardIcon(QStyle::SP_ComputerIcon),
+        "", m_generalPurposeToolbar);
+    m_generalPurposeToolbar->addAction(commandAction);
+    m_generalPurposeToolbar->addAction(computerAction);
+    addToolBar(m_generalPurposeToolbar);
+
+    // Create status bar.
+
+    m_statusBar = new QStatusBar(this);
+    setStatusBar(m_statusBar);
+
+    readSettings();
+
+    connect(m_filesDockWidget, SIGNAL(openFile(QString)), this, SLOT(handleOpenFileRequest(QString)));
+    connect(m_historyDockWidget, SIGNAL(information(QString)), this, SLOT(reportStatusMessage(QString)));
+    connect(m_historyDockWidget, SIGNAL(commandDoubleClicked(QString)), this, SLOT(handleCommandDoubleClicked(QString)));
+    connect(m_variablesDockWidget, SIGNAL(saveWorkspace()), this, SLOT(handleSaveWorkspaceRequest()));
+    connect(m_variablesDockWidget, SIGNAL(loadWorkspace()), this, SLOT(handleLoadWorkspaceRequest()));
+    connect(m_variablesDockWidget, SIGNAL(clearWorkspace()), this, SLOT(handleClearWorkspaceRequest()));
+
+    m_browserDockWidget->browserWidget()->load(QUrl("http://www.gnu.org/software/octave/doc/interpreter/"));
+    m_serviceDockWidget->browserWidget()->load(QUrl("http://powerup.ath.cx/bugtracker"));
+
+}
+
+void MainWindow::establishOctaveLink() {
+    m_octaveMainThread = new OctaveMainThread(this);
+    m_octaveMainThread->start();
+
+    m_octaveCallbackThread = new OctaveCallbackThread(this, this);
+    m_octaveCallbackThread->start();
+
+    command_editor::add_event_hook(OctaveLink::readlineEventHook);
+
+    int fdm, fds;
+    if(openpty(&fdm, &fds, 0, 0, 0) < 0) {
+        assert(0);
+    }
+    dup2 (fds, 0);
+    dup2 (fds, 1);
+    dup2 (fds, 2);
+    m_octaveTerminalDockWidget->octaveTerminal()->openTeletype(fdm);
+    reportStatusMessage(tr("Established link to Octave."));
+}
new file mode 100644
--- /dev/null
+++ b/gui/src/MainWindow.h
@@ -0,0 +1,180 @@
+/* Quint - A graphical user interface for Octave
+ * Copyright (C) 2011 Jacob Dawid
+ * jacob.dawid@googlemail.com
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
+
+#include <QtGui/QMainWindow>
+#include <QThread>
+#include <QTabWidget>
+#include <QMdiArea>
+#include <QStatusBar>
+#include <QToolBar>
+#include <QQueue>
+#include "OctaveTerminal.h"
+#include "OctaveLink.h"
+#include "VariablesDockWidget.h"
+#include "HistoryDockWidget.h"
+#include "FilesDockWidget.h"
+#include "SimpleEditor.h"
+#include "BrowserWidget.h"
+
+// Octave includes
+#undef PACKAGE_BUGREPORT
+#undef PACKAGE_NAME
+#undef PACKAGE_STRING
+#undef PACKAGE_TARNAME
+#undef PACKAGE_VERSION
+#undef PACKAGE_URL
+#include "octave/config.h"
+
+#include "octave/debug.h"
+#include "octave/octave.h"
+#include "octave/symtab.h"
+#include "octave/parse.h"
+#include "octave/unwind-prot.h"
+#include "octave/toplev.h"
+#include "octave/load-path.h"
+#include "octave/error.h"
+#include "octave/quit.h"
+#include "octave/variables.h"
+#include "octave/sighandlers.h"
+#include "octave/sysdep.h"
+#include "octave/str-vec.h"
+#include "octave/cmd-hist.h"
+#include "octave/cmd-edit.h"
+#include "octave/oct-env.h"
+#include "octave/symtab.h"
+#include "cmd-edit.h"
+
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+extern OCTINTERP_API YY_BUFFER_STATE create_buffer (FILE *f);
+extern OCTINTERP_API void switch_to_buffer (YY_BUFFER_STATE buf);
+extern OCTINTERP_API FILE *get_input_from_stdin (void);
+
+// System
+#include <termios.h>
+#include <sys/types.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <iostream>
+#include <vector>
+#include "pty.h"
+
+class OctaveMainThread;
+class OctaveCallbackThread;
+
+/**
+  * \class MainWindow
+  *
+  * Represents the main window.
+  */
+class MainWindow : public QMainWindow {
+    Q_OBJECT
+public:
+    MainWindow(QWidget *parent = 0);
+    ~MainWindow();
+
+    bool isRunning() { return m_isRunning; }
+    OctaveTerminal *octaveTerminal() { return m_octaveTerminalDockWidget->octaveTerminal(); }
+    VariablesDockWidget *variablesDockWidget() { return m_variablesDockWidget; }
+    HistoryDockWidget *historyDockWidget() { return m_historyDockWidget; }
+    FilesDockWidget *filesDockWidget() { return m_filesDockWidget; }
+
+public slots:
+    void handleOpenFileRequest(QString fileName);
+    void reportStatusMessage(QString statusMessage);
+    void handleSaveWorkspaceRequest();
+    void handleLoadWorkspaceRequest();
+    void handleClearWorkspaceRequest();
+    void handleCommandDoubleClicked(QString command);
+
+protected:
+    void closeEvent(QCloseEvent *closeEvent);
+    void readSettings();
+    void writeSettings();
+
+private:
+    void construct();
+    void establishOctaveLink();
+    OctaveTerminalDockWidget *m_octaveTerminalDockWidget;
+    VariablesDockWidget *m_variablesDockWidget;
+    HistoryDockWidget *m_historyDockWidget;
+    FilesDockWidget *m_filesDockWidget;    
+    BrowserDockWidget *m_browserDockWidget;
+    BrowserDockWidget *m_serviceDockWidget;
+
+    QStatusBar *m_statusBar;
+    QToolBar *m_generalPurposeToolbar;
+    QString m_settingsFile;
+
+    // Threads for running octave and managing the data interaction.
+    OctaveMainThread *m_octaveMainThread;
+    OctaveCallbackThread *m_octaveCallbackThread;
+    bool m_isRunning;
+};
+
+class OctaveMainThread : public QThread {
+    Q_OBJECT
+public:
+    OctaveMainThread(QObject *parent)
+        : QThread(parent) {
+    }
+protected:
+    void run() {
+        int argc = 3;
+        const char* argv[] = {"octave", "--interactive", "--line-editing"};
+        octave_main(argc, (char**)argv, 1);
+        main_loop();
+        clean_up_and_exit(0);
+    }
+};
+
+class OctaveCallbackThread : public QThread {
+    Q_OBJECT
+public:
+    OctaveCallbackThread(QObject *parent, MainWindow *mainWindow)
+        : QThread(parent),
+          m_mainWindow(mainWindow) {
+    }
+
+protected:
+    void run() {
+        while(m_mainWindow->isRunning()) {
+
+        // Get a full variable list.
+        QList<SymbolRecord> symbolTable = OctaveLink::instance()->currentSymbolTable();
+        if(symbolTable.size()) {
+            m_mainWindow->variablesDockWidget()->setVariablesList(symbolTable);
+        }
+
+        // Collect history list.
+        string_vector historyList = OctaveLink::instance()->currentHistory();
+        if(historyList.length()) {
+            m_mainWindow->historyDockWidget()->updateHistory(historyList);
+        }
+
+            usleep(100000);
+        }
+    }
+private:
+    MainWindow *m_mainWindow;
+};
+
+#endif // MAINWINDOW_H
new file mode 100644
--- /dev/null
+++ b/gui/src/NumberedCodeEdit.cpp
@@ -0,0 +1,591 @@
+/* This file is part of the KDE libraries
+    Copyright (C) 2005, 2006 KJSEmbed Authors
+    See included AUTHORS file.
+
+    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 <QTextDocument>
+#include <QTextBlock>
+#include <QHBoxLayout>
+#include <QScrollBar>
+#include <QPainter>
+#include <QAbstractTextDocumentLayout>
+#include <QToolTip>
+#include <QTextStream>
+#include <QProcess>
+#include <QRegExp>
+#include <QMessageBox>
+#include <QFileInfo>
+
+#include "NumberedCodeEdit.h"
+#include "config.h"
+
+NumberBar::NumberBar( QWidget *parent )
+    : QWidget( parent ), edit(0), currentLine(-1), bugLine(-1)
+{
+    // Make room for 4 digits and the breakpoint icon
+    setFixedWidth( fontMetrics().width( QString("0000") + 10 + 32 ) );
+    stopMarker = QPixmap();// QString(ICON_PATH) + "/stop.png" );
+    currentMarker = QPixmap();// QString(ICON_PATH) + "/bookmark.png" );
+    bugMarker = QPixmap();// QString(ICON_PATH) + "/bug.png" );
+}
+
+NumberBar::~NumberBar()
+{
+}
+
+void NumberBar::setCurrentLine( int lineno )
+{
+    currentLine = lineno;
+    update();
+}
+
+void NumberBar::setBugLine( int lineno )
+{
+    bugLine = lineno;
+}
+
+void NumberBar::toggleBreakpoint( int lineno )
+{
+  if(lineno > 0)
+  {
+    int i = breakpoints.indexOf(lineno);
+
+    if(i > -1)
+      breakpoints.removeAt(i);
+    else
+      breakpoints.push_back(lineno);
+  }
+  update();
+}
+
+void NumberBar::setTextEdit( SimpleEditor *edit )
+{
+    this->edit = edit;
+    setFixedWidth( edit->fontMetrics().width( QString("0000") + 10 + 32 ) );
+    connect( edit->document()->documentLayout(), SIGNAL( update(const QRectF &) ),
+	     this, SLOT( update() ) );
+    connect( edit->verticalScrollBar(), SIGNAL(valueChanged(int) ),
+	     this, SLOT( update() ) );
+}
+
+void NumberBar::paintEvent( QPaintEvent * )
+{
+    QVector<qreal> lines_list;
+    int first_line_no;
+    edit->publicBlockBoundingRectList(lines_list, first_line_no);
+    
+    const QFontMetrics fm = edit->fontMetrics();
+    const int ascent = fontMetrics().ascent(); // height = ascent + descent
+   
+    QPainter p(this);
+    p.setPen(palette().windowText().color());
+    
+    bugRect = QRect();
+    stopRect = QRect();
+    currentRect = QRect();
+    
+    int position_y;
+    int lineCount;
+    
+    const int lines_list_size=lines_list.size();
+    
+    for(int i=0;i<lines_list_size;i++)
+    {
+    	position_y=qRound( lines_list[i] );
+    	lineCount=first_line_no+i;
+    	
+    	const QString txt = QString::number( lineCount );
+        p.drawText( width() - fm.width(txt)- 2, position_y+ascent, txt );
+        
+        // Bug marker
+	if ( bugLine == lineCount ) {
+	    p.drawPixmap( 1, position_y, bugMarker );
+	    bugRect = QRect( 19, position_y, bugMarker.width(), bugMarker.height() );
+	}
+	
+	// Stop marker
+	if ( breakpoints.contains(lineCount) ) {
+	    p.drawPixmap( 1, position_y, stopMarker );
+	    stopRect = QRect( 1, position_y,stopMarker.width(),  stopMarker.height() );
+	}
+	
+	// Current line marker
+	if ( currentLine == lineCount ) {
+	    p.drawPixmap( 1, position_y, currentMarker );
+	    currentRect = QRect( 1, position_y, currentMarker.width(), currentMarker.height() );
+	}
+    }
+    
+    /*
+    
+    int contentsY = edit->verticalScrollBar()->value();
+    qreal pageBottom = contentsY + edit->viewport()->height();
+    const QFontMetrics fm = fontMetrics();
+    const int ascent = fontMetrics().ascent() + 1; // height = ascent + descent + 1
+    int lineCount = 1;
+
+    QPainter p(this);
+    p.setPen(palette().windowText().color());
+
+    bugRect = QRect();
+    stopRect = QRect();
+    currentRect = QRect();
+
+    for ( QTextBlock block = edit->document()->begin();
+	  block.isValid(); block = block.next(), ++lineCount ) {
+
+        const QRectF boundingRect = edit->publicBlockBoundingRect( block );
+
+        QPointF position = boundingRect.topLeft();
+        if ( position.y() + boundingRect.height() < contentsY )
+            continue;
+        if ( position.y() > pageBottom )
+            break;
+
+        const QString txt = QString::number( lineCount );
+        p.drawText( width() - fm.width(txt), qRound( position.y() ) - contentsY + ascent, txt );
+
+	// Bug marker
+	if ( bugLine == lineCount ) {
+	    p.drawPixmap( 1, qRound( position.y() ) - contentsY, bugMarker );
+	    bugRect = QRect( 1, qRound( position.y() ) - contentsY, bugMarker.width(), bugMarker.height() );
+	}
+
+	// Stop marker
+	if ( breakpoints.contains(lineCount) ) {
+	    p.drawPixmap( 19, qRound( position.y() ) - contentsY, stopMarker );
+	    stopRect = QRect( 19, qRound( position.y() ) - contentsY, stopMarker.width(), stopMarker.height() );
+	}
+
+	// Current line marker
+	if ( currentLine == lineCount ) {
+	    p.drawPixmap( 19, qRound( position.y() ) - contentsY, currentMarker );
+	    currentRect = QRect( 19, qRound( position.y() ) - contentsY, currentMarker.width(), currentMarker.height() );
+	}
+    }
+    */
+}
+
+bool NumberBar::event( QEvent *event )
+{
+    if ( event->type() == QEvent::ToolTip ) {
+	QHelpEvent *helpEvent = static_cast<QHelpEvent *>(event);
+
+	if ( stopRect.contains( helpEvent->pos() ) ) {
+	    QToolTip::showText( helpEvent->globalPos(), tr("Stop Here"));
+	}
+	else if ( currentRect.contains( helpEvent->pos() ) ) {
+	    QToolTip::showText( helpEvent->globalPos(), tr("Current Line"));
+	}
+	else if ( bugRect.contains( helpEvent->pos() ) ) {
+	    QToolTip::showText( helpEvent->globalPos(), tr("Error Line" ));
+	}
+    }
+
+    return QWidget::event(event);
+}
+
+QList<int> *NumberBar::getBreakpoints()
+{
+  return &breakpoints;
+}
+
+
+
+NumberedCodeEdit::NumberedCodeEdit( QWidget *parent, SimpleEditor *textEdit )
+    : QFrame( parent )
+{
+	setFrameStyle( QFrame::StyledPanel | QFrame::Sunken );
+	setLineWidth( 2 );
+	
+	view=textEdit;
+        view->installEventFilter( this );
+	
+	connect( view->document(), SIGNAL(contentsChange(int,int,int)), this, SLOT(textChanged(int,int,int)) );
+	
+	connect( view, SIGNAL(cursorPositionChanged()), this, SLOT(cursor_moved_cb()) );
+	
+	// Setup the line number pane
+	
+	numbers = new NumberBar( this );
+	numbers->setTextEdit( view );
+	//numbers=NULL;
+	
+	
+	vbox = new QVBoxLayout(this);
+	vbox->setSpacing( 0 );
+	vbox->setMargin( 0 );
+	
+	hbox = new QHBoxLayout;
+	vbox->addLayout(hbox);
+	
+	hbox->setSpacing( 0 );
+	hbox->setMargin( 0 );
+	hbox->addWidget( numbers );
+	hbox->addWidget( view );
+
+	textModifiedOk=false;
+	
+	QHBoxLayout *messages_layout= new QHBoxLayout;
+	vbox->addLayout(messages_layout);
+	messages_layout->setSpacing( 0 );
+	messages_layout->setMargin( 0 );
+	}
+
+
+NumberedCodeEdit::~NumberedCodeEdit()
+{
+	hide();
+	//printf("Borrado ntv\n");
+}
+
+void NumberedCodeEdit::setCurrentLine( int lineno )
+{
+	currentLine = lineno;
+	if(numbers!=NULL) numbers->setCurrentLine( lineno );
+	
+	//Move cursor to lineno
+	if(lineno>-1)
+	{
+		QTextCursor cursor=textEdit()->textCursor();
+		
+		cursor.movePosition(QTextCursor::Start);
+		
+		for(int i=1;i<lineno;i++)
+			cursor.movePosition(QTextCursor::NextBlock);
+		
+		textEdit()->setTextCursor(cursor);
+	}
+	
+	textChanged( 0, 0, 1 );
+}
+
+void NumberedCodeEdit::toggleBreakpoint( int lineno )
+{
+	if(numbers!=NULL) numbers->toggleBreakpoint( lineno );
+}
+
+void NumberedCodeEdit::setBugLine( int lineno )
+{
+	if(numbers!=NULL) numbers->setBugLine( lineno );
+}
+
+void NumberedCodeEdit::textChanged( int /*pos*/, int removed, int added )
+{
+    //Q_UNUSED( pos );
+
+    if ( removed == 0 && added == 0 )
+	return;
+
+    //QTextBlock block = highlight.block();
+    //QTextBlock block = view->document()->begin();
+    //QTextBlockFormat fmt = block.blockFormat();
+    //QColor bg = view->palette().base().color();
+    //fmt.setBackground( bg );
+    //highlight.setBlockFormat( fmt );
+    /*
+    QTextBlockFormat fmt;
+
+    int lineCount = 1;
+    for ( QTextBlock block = view->document()->begin();
+	  block.isValid() && block!=view->document()->end(); block = block.next(), ++lineCount ) {
+
+	if ( lineCount == currentLine )
+	{
+	    fmt = block.blockFormat();
+	    QColor bg = view->palette().highlight().color();
+	    fmt.setBackground( bg );
+
+	    highlight = QTextCursor( block );
+	    highlight.movePosition( QTextCursor::EndOfBlock, QTextCursor::KeepAnchor );
+	    highlight.setBlockFormat( fmt );
+
+	    break;
+	}
+    }
+    */
+    
+    if( !textModifiedOk && view->document()->isModified() )
+    {
+    	textModifiedOk=true;
+    	emit textModified();
+    }
+}
+
+bool NumberedCodeEdit::eventFilter( QObject *obj, QEvent *event )
+{
+    if ( obj != view )
+	return QFrame::eventFilter(obj, event);
+
+    if ( event->type() == QEvent::ToolTip ) {
+	QHelpEvent *helpEvent = static_cast<QHelpEvent *>(event);
+
+	QTextCursor cursor = view->cursorForPosition( helpEvent->pos() );
+	cursor.movePosition( QTextCursor::StartOfWord, QTextCursor::MoveAnchor );
+	cursor.movePosition( QTextCursor::EndOfWord, QTextCursor::KeepAnchor );
+
+	QString word = cursor.selectedText();
+	emit mouseHover( word );
+	emit mouseHover( helpEvent->pos(), word );
+
+	// QToolTip::showText( helpEvent->globalPos(), word ); // For testing
+    }
+
+    return false;
+}
+
+QList<int> *NumberedCodeEdit::getBreakpoints()
+{
+	QList<int> *br=NULL;
+	if(numbers!=NULL) br=numbers->getBreakpoints();
+	return br;
+}
+
+void NumberedCodeEdit::open(QString path)
+{
+  FILE *fl;
+
+  fl = fopen(path.toLocal8Bit().constData(), "rt");
+  if(fl)
+  {
+	fclose(fl);
+	filePath = path;
+	
+	textEdit()->load(path);
+	
+	textModifiedOk=false;
+	textEdit()->document()->setModified(false);
+  }else{
+    throw path;
+  }
+}
+
+bool NumberedCodeEdit::save(QString path)
+{
+  FILE *fl;
+
+  if(path.isEmpty()) path = filePath;
+  QRegExp re("[A-Za-z_][A-Za-z0-9_]*\\.m");
+  
+  if( ! re.exactMatch( QFileInfo(path).fileName() ) )
+  {
+	QMessageBox msgBox;
+	msgBox.setText( tr("This file name is not valid.") );
+	msgBox.setInformativeText(tr("Octave doesn't understand this file name:\n")+path+tr("\nPlease, change it.\n Do you want to save your changes?"));
+	msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Cancel);
+	msgBox.setDefaultButton(QMessageBox::Save);
+	int ret = msgBox.exec();
+	switch (ret)
+	{
+		case QMessageBox::Save:
+		    // Save was clicked
+		    break;
+		case QMessageBox::Cancel:
+		    // Cancel was clicked
+		    	return false;
+		    break;
+		default:
+		    // should never be reached
+		    break;
+	}
+  }
+  
+  
+  fl = fopen(path.toLocal8Bit().constData(), "wt");
+  if(fl)
+  {
+    filePath = path;
+    QTextStream *stream = new QTextStream(fl);
+    (*stream) << textEdit()->document()->toPlainText();
+    delete stream;
+    fclose(fl);
+    textModifiedOk=false;
+    view->document()->setModified(false);
+  }else{
+    return false;
+  }
+  
+  return true;
+}
+
+QString NumberedCodeEdit::path()
+{
+  return filePath;
+}
+
+void NumberedCodeEdit::setPath(QString path)
+{
+	filePath=path;
+	textEdit()->setFile(path);
+}
+
+void NumberedCodeEdit::setModified(bool modify)
+{
+	textModifiedOk=modify;
+}
+
+bool NumberedCodeEdit::modified()
+{
+	return textModifiedOk;
+}
+
+void NumberedCodeEdit::cursor_moved_cb()
+{
+	QTextCursor cursor=view->textCursor();
+	QTextBlock actual_block=cursor.block();
+	int lineCount=1;
+	QTextBlock block = view->document()->begin();
+	
+	for ( ;block.isValid() && actual_block!=block; block = block.next()) lineCount++ ;
+}
+
+static QString startLineInsertText(QString str, QString textToInsert)
+{
+	str.replace(QChar(0x2029), "\n");
+	//printf("str=%s\n", str.toLocal8Bit().data() );
+	
+	QStringList list = str.split("\n");
+	
+	for(int i=0;i<list.size();i++)
+	{
+		QString s=list[i];
+		
+		int x;
+		
+		for(x=0;x<s.size();x++)
+		{
+			if( s.at(x)!=' ' && s.at(x)!='\t' ) break;
+		}
+		
+		QString s1=s.left(x);
+                QString s2=s.right(s.size()-x);
+		list[i]=s1+textToInsert+s2;
+	}
+	
+	return list.join("\n");
+}
+
+static QString startLineRemoveText(QString str, QStringList textToRemove)
+{
+	str.replace(QChar(0x2029), "\n");
+	
+	QStringList list = str.split("\n");
+	
+	for(int i=0;i<list.size();i++)
+	{
+		QString s=list[i];
+		
+		int x;
+		
+		for(x=0;x<s.size();x++)
+		{
+			if( s.at(x)!=' ' && s.at(x)!='\t' ) break;
+		}
+		
+		QString s1=s.left(x);
+		QString s2=s.right(s.size()-x);
+		
+		for(int k=0;k<textToRemove.size();k++)
+		{
+			if(s1.endsWith(textToRemove[k]))
+			{
+				s1=s1.left(s1.size()-textToRemove[k].size());
+				break;
+			}
+			else if(s2.startsWith(textToRemove[k]))
+			{
+				s2=s2.right(s2.size()-textToRemove[k].size());
+				break;
+			}
+		}
+		
+		//printf("s1=%s s2=%s \n", s1.toLocal8Bit().data(), s2.toLocal8Bit().data());
+		list[i]=s1+s2;
+	}
+	
+	return list.join("\n");
+}
+
+void NumberedCodeEdit::indent()
+{
+	QTextCursor cursor(textEdit()->textCursor());
+	
+	if( !cursor.hasSelection() ) return;
+	
+	QString str=cursor.selectedText();
+	
+	str=startLineInsertText(str, "\t");
+	
+	cursor.insertText(str);
+	cursor.setPosition(cursor.position()-str.size(), QTextCursor::KeepAnchor);
+	textEdit()->setTextCursor(cursor);
+}
+
+void NumberedCodeEdit::unindent()
+{
+	//QTextDocument *doc=textEdit()->document();
+	
+	QTextCursor cursor(textEdit()->textCursor());
+	
+	if( !cursor.hasSelection() ) return;
+	
+	QString str=cursor.selectedText();
+	
+	QStringList textToRemove;
+	textToRemove << "\t" << " ";
+	str=startLineRemoveText(str, textToRemove);
+	
+	cursor.insertText(str);
+	cursor.setPosition(cursor.position()-str.size(), QTextCursor::KeepAnchor);
+	textEdit()->setTextCursor(cursor);
+}
+
+void NumberedCodeEdit::comment()
+{
+	//QTextDocument *doc=textEdit()->document();
+	
+	QTextCursor cursor(textEdit()->textCursor());
+	
+	if( !cursor.hasSelection() ) return;
+	
+	QString str=cursor.selectedText();
+	
+	str=startLineInsertText(str, "%");
+	
+	cursor.insertText(str);
+	cursor.setPosition(cursor.position()-str.size(), QTextCursor::KeepAnchor);
+	textEdit()->setTextCursor(cursor);
+}
+
+void NumberedCodeEdit::uncomment()
+{
+	//QTextDocument *doc=textEdit()->document();
+	
+	QTextCursor cursor(textEdit()->textCursor());
+	
+	if( !cursor.hasSelection() ) return;
+	
+	QString str=cursor.selectedText();
+	
+	QStringList textToRemove;
+	textToRemove << "%" << "#";
+	str=startLineRemoveText(str, textToRemove);
+	
+	cursor.insertText(str);
+	cursor.setPosition(cursor.position()-str.size(), QTextCursor::KeepAnchor);
+	textEdit()->setTextCursor(cursor);
+}
new file mode 100644
--- /dev/null
+++ b/gui/src/NumberedCodeEdit.h
@@ -0,0 +1,169 @@
+/* This file is part of the KDE libraries
+    Copyright (C) 2005, 2006 KJSEmbed Authors
+    See included AUTHORS file.
+
+    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.
+*/
+// -*- c++ -*-
+#ifndef NUMBERED_TEXT_VIEW_H
+#define NUMBERED_TEXT_VIEW_H
+
+#include <QFrame>
+#include <QPixmap>
+#include <QTextCursor>
+#include <QLabel>
+#include <QVBoxLayout>
+#include <QHBoxLayout>
+#include "SimpleEditor.h"
+
+class SimpleEditor;
+class QHBoxLayout;
+
+/**
+ * @internal Used to display the numbers.
+ */
+class NumberBar : public QWidget
+{
+    Q_OBJECT
+
+public:
+    NumberBar( QWidget *parent );
+    ~NumberBar();
+
+    void setCurrentLine( int lineno );
+    void setBugLine( int lineno );
+    void toggleBreakpoint( int lineno );
+    QList<int> *getBreakpoints();
+
+    void setTextEdit( SimpleEditor *edit );
+    void paintEvent( QPaintEvent *ev );
+
+protected:
+    bool event( QEvent *ev );
+
+private:
+    SimpleEditor *edit;
+    QPixmap stopMarker;
+    QPixmap currentMarker;
+    QPixmap bugMarker;
+    QList<int> breakpoints;
+    int currentLine;
+    int bugLine;
+    QRect stopRect;
+    QRect currentRect;
+    QRect bugRect;
+};
+
+/**
+ * Displays a CodeEdit with line numbers.
+ */
+class NumberedCodeEdit : public QFrame
+{
+    Q_OBJECT
+
+public:
+    NumberedCodeEdit( QWidget *parent = 0 , SimpleEditor *textEdit=new SimpleEditor() );
+    ~NumberedCodeEdit();
+
+    QList<int> *getBreakpoints();
+
+    void open(QString path);
+    
+    /**Saves file to path. @return true if all is OK.*/
+    bool save(QString path = QString());
+
+    QString path();
+    void setPath(QString path);
+    
+    bool modified();
+    void setModified(bool modify);
+
+    /** Returns the CodeEdit of the main view. */
+    SimpleEditor *textEdit() const { return view; }
+
+    /**
+     * Sets the line that should have the current line indicator.
+     * A value of -1 indicates no line should show the indicator.
+     */
+    void setCurrentLine( int lineno );
+
+    /**
+     * Toggle breakpoint
+     */
+    void toggleBreakpoint( int lineno );
+
+    /**
+     * Sets the line that should have the bug line indicator.
+     * A value of -1 indicates no line should show the indicator.
+     */
+    void setBugLine( int lineno );
+
+    /** @internal Used to get tooltip events from the view for the hover signal. */
+    bool eventFilter( QObject *obj, QEvent *event );
+    
+    /**Indent selected text.*/
+    void indent();
+    
+    /**UnIndent selected text.*/
+    void unindent();
+    
+    /**Comment selected text.*/
+    void comment();
+    
+    /**UnComment selected text.*/
+    void uncomment();
+
+signals:
+    /**
+     * Emitted when the mouse is hovered over the text edit component.
+     * @param word The word under the mouse pointer
+     */
+    void mouseHover( const QString &word );
+
+    /**
+     * Emitted when the mouse is hovered over the text edit component.
+     * @param pos The position of the mouse pointer.
+     * @param word The word under the mouse pointer
+     */
+    void mouseHover( const QPoint &pos, const QString &word );
+    
+    /**
+     * Emitted when file is changed.
+     */
+    void textModified();
+
+protected slots:
+    /** @internal Used to update the highlight on the current line. */
+    void textChanged( int pos, int added, int removed );
+public slots:
+    void cursor_moved_cb();
+
+private:
+    QString filePath;
+    QLabel *line_column_label;
+    SimpleEditor *view;
+    NumberBar *numbers;
+    QHBoxLayout *hbox;
+    QVBoxLayout *vbox;
+    int currentLine;
+    QTextCursor highlight;
+    bool textModifiedOk;
+};
+
+
+#endif // NUMBERED_TEXT_VIEW_H
+
+
new file mode 100644
--- /dev/null
+++ b/gui/src/OctaveLink.cpp
@@ -0,0 +1,132 @@
+/*
+
+Copyright (C) 2007,2008,2009 John P. Swensen
+
+Octave 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, or (at your option) any
+later version.
+
+Octave 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 Octave; see the file COPYING.  If not, write to the Free
+Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.
+
+*/
+
+// Born July 13, 2007.
+
+#include "OctaveLink.h"
+
+OctaveLink OctaveLink::m_singleton;
+
+
+OctaveLink::OctaveLink()
+    : QObject(),
+      m_previousHistoryLength(0) {
+    m_symbolTableSemaphore = new QSemaphore(1);
+    m_historySemaphore = new QSemaphore(1);
+}
+
+OctaveLink::~OctaveLink() {
+}
+
+int OctaveLink::readlineEventHook() {
+  OctaveLink::instance()->processOctaveServerData();
+  return 0;
+}
+
+QString OctaveLink::octaveValueAsQString(OctaveValue octaveValue) {
+    // Convert single qouted string.
+    if(octaveValue.is_sq_string()) {
+        return QString("\'%1\'").arg(octaveValue.string_value().c_str());
+
+    // Convert double qouted string.
+    } else if(octaveValue.is_dq_string()) {
+        return QString("\"%1\"").arg(octaveValue.string_value().c_str());
+
+    // Convert real scalar.
+    } else if(octaveValue.is_real_scalar()) {
+        return QString("%1").arg(octaveValue.scalar_value());
+
+    // Convert complex scalar.
+    } else if(octaveValue.is_complex_scalar()) {
+        return QString("%1 + %2i").arg(octaveValue.scalar_value()).arg(octaveValue.complex_value().imag());
+
+    // Convert range.
+    } else if(octaveValue.is_range()) {
+        return QString("%1 : %2 : %3").arg(octaveValue.range_value().base())
+                                      .arg(octaveValue.range_value().inc())
+                                      .arg(octaveValue.range_value().limit());
+
+    // Convert real matrix.
+    } else if(octaveValue.is_real_matrix()) {
+        // TODO: Convert real matrix into a string.
+        return QString("{matrix}");
+
+    // Convert complex matrix.
+    } else if(octaveValue.is_complex_matrix()) {
+        // TODO: Convert complex matrix into a string.
+        return QString("{complex matrix}");
+
+    // If everything else does not fit, we could not recognize the type.
+    } else {
+        return QString("<Type not recognized>");
+    }
+}
+
+void OctaveLink::fetchSymbolTable() {
+    m_symbolTableSemaphore->acquire();
+    m_symbolTableBuffer.clear();
+    std::list<SymbolRecord> allVariables = symbol_table::all_variables();
+    std::list<SymbolRecord>::iterator iterator;
+    for(iterator = allVariables.begin(); iterator != allVariables.end(); iterator++)
+        m_symbolTableBuffer.append(*iterator);
+    m_symbolTableSemaphore->release();
+    emit symbolTableChanged();
+}
+
+
+void OctaveLink::fetchHistory() {
+    int currentLen = command_history::length();
+    if(currentLen != m_previousHistoryLength) {
+        m_historySemaphore->acquire();
+        for(int i = m_previousHistoryLength; i < currentLen; i++) {
+            m_historyBuffer.append(command_history::get_entry(i));
+        }
+        m_historySemaphore->release();
+        m_previousHistoryLength = currentLen;
+        emit historyChanged();
+    }
+}
+
+QList<SymbolRecord> OctaveLink::currentSymbolTable() {
+    QList<SymbolRecord> m_symbolTableCopy;
+
+    // Generate a deep copy of the current symbol table.
+    m_symbolTableSemaphore->acquire();
+    foreach(SymbolRecord symbolRecord, m_symbolTableBuffer)
+        m_symbolTableCopy.append(symbolRecord);
+    m_symbolTableSemaphore->release();
+
+    return m_symbolTableCopy;
+}
+
+string_vector OctaveLink::currentHistory() {
+    m_historySemaphore->acquire();
+    string_vector retval(m_historyBuffer);
+    m_historyBuffer = string_vector();
+    m_historySemaphore->release();
+    return retval;
+}
+
+void OctaveLink::processOctaveServerData() {
+    fetchSymbolTable();
+    fetchHistory();
+}
+
new file mode 100644
--- /dev/null
+++ b/gui/src/OctaveLink.h
@@ -0,0 +1,139 @@
+/*
+ *
+ * Copyright (C) 2007, 2008, 2009 John P. Swensen
+ *
+ * This file is as a part of OctaveDE.
+ *
+ * Octave 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, or (at your option) any
+ * later version.
+ *
+ * Octave 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 Octave; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * */
+#ifndef OCTAVELINK_H
+#define OCTAVELINK_H
+
+// Octave includes
+#undef PACKAGE_BUGREPORT
+#undef PACKAGE_NAME
+#undef PACKAGE_STRING
+#undef PACKAGE_TARNAME
+#undef PACKAGE_VERSION
+#undef PACKAGE_URL
+#include <octave/config.h>
+#include "octave/cmd-edit.h"
+#include "octave/error.h"
+#include "octave/file-io.h"
+#include "octave/input.h"
+#include "octave/lex.h"
+#include "octave/load-path.h"
+#include "octave/octave.h"
+#include "octave/oct-hist.h"
+#include "octave/oct-map.h"
+#include "octave/oct-obj.h"
+#include "octave/ops.h"
+#include "octave/ov.h"
+#include "octave/ov-usr-fcn.h"
+#include "octave/symtab.h"
+#include "octave/pt.h"
+#include "octave/pt-eval.h"
+#include "octave/config.h"
+#include "octave/Range.h"
+#include "octave/toplev.h"
+#include "octave/procstream.h"
+#include "octave/sighandlers.h"
+#include "octave/debug.h"
+#include "octave/sysdep.h"
+#include "octave/ov.h"
+#include "octave/unwind-prot.h"
+#include "octave/utils.h"
+#include "octave/variables.h"
+
+// Standard includes
+#include <iostream>
+#include <string>
+#include <vector>
+#include <readline/readline.h>
+
+// Qt includes
+#include <QMutexLocker>
+#include <QMutex>
+#include <QFileInfo>
+#include <QList>
+#include <QString>
+#include <QVector>
+#include <QSemaphore>
+#include <QObject>
+
+typedef symbol_table::symbol_record SymbolRecord;
+typedef octave_value OctaveValue;
+
+/**
+  * \class OctaveLink
+  * Manages a link to an octave instance.
+  */
+class OctaveLink : QObject
+{
+    Q_OBJECT
+public:
+    static OctaveLink *instance() { return &m_singleton; }
+    static int readlineEventHook(void);
+    static QString octaveValueAsQString(OctaveValue octaveValue);
+
+    /**
+      * Returns a copy of the current symbol table buffer.
+      * \return Copy of the current symbol table buffer.
+      */
+    QList<SymbolRecord> currentSymbolTable();
+
+    /**
+      * Returns a copy of the current history buffer.
+      * \return Copy of the current history buffer.
+      */
+    string_vector currentHistory();
+
+    void processOctaveServerData();
+
+    /**
+      * Updates the current symbol table with new data
+      * from octave.
+      */
+    void fetchSymbolTable();
+
+    /**
+      * Updates the current history buffer with new data
+      * from octave.
+      */
+    void fetchHistory();
+
+signals:
+    void symbolTableChanged();
+    void historyChanged();
+
+private:
+    OctaveLink();
+    ~OctaveLink();
+
+    /** Variable related member variables. */
+    QSemaphore *m_symbolTableSemaphore;
+    QList<SymbolRecord> m_symbolTableBuffer;
+
+    /** History related member variables. */
+    QSemaphore *m_historySemaphore;
+    string_vector m_historyBuffer;
+    int m_previousHistoryLength;
+
+    static OctaveLink m_singleton;
+};
+#endif // OCTAVELINK_H
+
new file mode 100644
--- /dev/null
+++ b/gui/src/OctaveTerminal.cpp
@@ -0,0 +1,52 @@
+/* Quint - A graphical user interface for Octave
+ * Copyright (C) 2011 Jacob Dawid
+ * jacob.dawid@googlemail.com
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "OctaveTerminal.h"
+#include <QHBoxLayout>
+#include <QVBoxLayout>
+#include <QStringListModel>
+#include <QStringList>
+
+OctaveTerminalDockWidget::OctaveTerminalDockWidget(QWidget *parent, OctaveTerminal *octaveTerminal)
+    : QDockWidget(parent) {
+    setObjectName("OctaveTerminalDockWidget");
+    setWindowTitle(tr("Octave terminal"));
+    m_octaveTerminal = octaveTerminal;
+    setWidget(m_octaveTerminal);
+}
+
+OctaveTerminalDockWidget::~OctaveTerminalDockWidget() {
+}
+
+OctaveTerminal *OctaveTerminalDockWidget::octaveTerminal() {
+    return m_octaveTerminal;
+}
+
+OctaveTerminal::OctaveTerminal(QWidget *parent)
+    : QTerminalWidget(0, parent) {
+    construct();
+}
+
+OctaveTerminal::~OctaveTerminal() {
+}
+
+void OctaveTerminal::construct() {
+    setScrollBarPosition(QTerminalWidget::ScrollBarRight);
+    setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+}
+
new file mode 100644
--- /dev/null
+++ b/gui/src/OctaveTerminal.h
@@ -0,0 +1,46 @@
+/* Quint - A graphical user interface for Octave
+ * Copyright (C) 2011 Jacob Dawid
+ * jacob.dawid@googlemail.com
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef OCTAVETERMINAL_H
+#define OCTAVETERMINAL_H
+
+#include "QTerminalWidget.h"
+#include <QDockWidget>
+
+class OctaveTerminal;
+class OctaveTerminalDockWidget : public QDockWidget {
+public:
+    OctaveTerminalDockWidget(QWidget *parent, OctaveTerminal *octaveTerminal);
+    ~OctaveTerminalDockWidget();
+
+    OctaveTerminal *octaveTerminal();
+
+private:
+    OctaveTerminal *m_octaveTerminal;
+};
+
+class OctaveTerminal : public QTerminalWidget {
+    Q_OBJECT
+public:
+    OctaveTerminal(QWidget *parent = 0);
+    ~OctaveTerminal();
+
+private:
+    void construct();
+};
+#endif // OCTAVETERMINAL_H
new file mode 100644
--- /dev/null
+++ b/gui/src/ProcessInfo.cpp
@@ -0,0 +1,1054 @@
+/*
+    Copyright 2007-2008 by Robert Knight <robertknight@gmail.countm>
+
+    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 "ProcessInfo.h"
+
+// Unix
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#include <pwd.h>
+
+// Qt
+#include <QtCore/QDir>
+#include <QtCore/QFileInfo>
+#include <QtCore/QRegExp>
+#include <QtCore/QTextStream>
+#include <QtCore/QStringList>
+#include <QtCore/QSet>
+
+// KDE
+#include "konsole_export.h"
+
+#if defined(Q_OS_MAC)
+#include <sys/sysctl.h>
+#include <libproc.h>
+#ifdef HAVE_SYS_PROC_INFO_H
+#include <sys/proc_info.h>
+#endif
+#ifdef HAVE_SYS_PROC_H
+#include <sys/proc.h>
+#endif
+//#include <kde_file.h>
+#define KDE_struct_stat struct stat
+#define KDE_stat ::stat
+#endif
+
+#if defined(Q_OS_FREEBSD)
+#include <sys/sysctl.h> //krazy:exclude=includes
+#include <sys/types.h>
+#include <sys/user.h>
+#include <sys/syslimits.h>
+#include <libutil.h>
+#endif
+
+ProcessInfo::ProcessInfo(int pid , bool enableEnvironmentRead)
+    : _fields( ARGUMENTS | ENVIRONMENT ) // arguments and environments
+                                         // are currently always valid,
+                                         // they just return an empty
+                                         // vector / map respectively
+                                         // if no arguments
+                                         // or environment bindings
+                                         // have been explicitly set
+    , _enableEnvironmentRead(enableEnvironmentRead)
+    , _pid(pid)
+    , _parentPid(0)
+    , _foregroundPid(0)
+    , _userId(0)
+    , _lastError(NoError)
+    , _userName(QString())
+    , _userHomeDir(QString())
+{
+}
+
+ProcessInfo::Error ProcessInfo::error() const { return _lastError; }
+void ProcessInfo::setError(Error error) { _lastError = error; }
+
+void ProcessInfo::update() 
+{
+    readProcessInfo(_pid,_enableEnvironmentRead);
+}
+
+QString ProcessInfo::validCurrentDir() const
+{
+   bool ok = false;
+
+   // read current dir, if an error occurs try the parent as the next
+   // best option
+   int currentPid = parentPid(&ok);
+   QString dir = currentDir(&ok);
+   while ( !ok && currentPid != 0 )
+   {
+       ProcessInfo* current = ProcessInfo::newInstance(currentPid);
+       current->update();
+       currentPid = current->parentPid(&ok); 
+       dir = current->currentDir(&ok);
+       delete current;
+   }
+
+   return dir;
+}
+
+QString ProcessInfo::format(const QString& input) const
+{
+   bool ok = false;
+
+   QString output(input);
+
+   // search for and replace known marker
+   output.replace("%u",userName());
+   output.replace("%n",name(&ok));
+   output.replace("%c",formatCommand(name(&ok),arguments(&ok),ShortCommandFormat));
+   output.replace("%C",formatCommand(name(&ok),arguments(&ok),LongCommandFormat));
+   
+   QString dir = validCurrentDir();
+   if (output.contains("%D"))
+   {
+      QString homeDir = userHomeDir();
+      QString tempDir = dir;
+      // Change User's Home Dir w/ ~ only at the beginning
+      if (tempDir.startsWith(homeDir))
+      {
+         tempDir.remove(0, homeDir.length());
+         tempDir.prepend('~');
+      }
+      output.replace("%D", tempDir);
+   }
+   output.replace("%d", dir);
+   
+   // remove any remaining %[LETTER] sequences
+   // output.replace(QRegExp("%\\w"), QString());
+
+   return output;
+}
+
+QString ProcessInfo::formatCommand(const QString& name, 
+                                   const QVector<QString>& arguments,
+                                   CommandFormat format) const
+{
+    Q_UNUSED(name);
+    Q_UNUSED(format);
+
+    // TODO Implement me
+    return QStringList(QList<QString>::fromVector(arguments)).join(" ");
+}
+
+QVector<QString> ProcessInfo::arguments(bool* ok) const
+{
+    *ok = _fields & ARGUMENTS;
+
+    return _arguments;
+}
+
+QMap<QString,QString> ProcessInfo::environment(bool* ok) const
+{
+    *ok = _fields & ENVIRONMENT;
+
+    return _environment;
+}
+
+bool ProcessInfo::isValid() const
+{
+    return _fields & PROCESS_ID;
+}
+
+int ProcessInfo::pid(bool* ok) const
+{
+    *ok = _fields & PROCESS_ID;
+
+    return _pid;
+}
+
+int ProcessInfo::parentPid(bool* ok) const
+{
+    *ok = _fields & PARENT_PID;
+
+    return _parentPid;
+}
+
+int ProcessInfo::foregroundPid(bool* ok) const
+{
+    *ok = _fields & FOREGROUND_PID;
+
+    return _foregroundPid;
+}
+
+QString ProcessInfo::name(bool* ok) const
+{
+    *ok = _fields & NAME;
+
+    return _name;
+}
+
+int ProcessInfo::userId(bool* ok) const
+{
+    *ok = _fields & UID;
+
+    return _userId;
+}
+
+QString ProcessInfo::userName() const
+{
+    return _userName;
+}
+
+QString ProcessInfo::userHomeDir() const
+{
+    return _userHomeDir;
+}
+
+void ProcessInfo::setPid(int pid)
+{
+    _pid = pid;
+    _fields |= PROCESS_ID;
+}
+
+void ProcessInfo::setUserId(int uid)
+{
+    _userId = uid;
+    _fields |= UID;
+}
+
+void ProcessInfo::setUserName(const QString& name)
+{
+    _userName = name;
+    setUserHomeDir();
+}
+
+void ProcessInfo::setUserHomeDir()
+{
+    QString usersName = userName();
+    // JPS: I don't know a good QT replacement
+    //if (!usersName.isEmpty())
+    //    _userHomeDir = KUser(usersName).homeDir();
+    //else
+        _userHomeDir = QDir::homePath();
+}
+
+void ProcessInfo::setParentPid(int pid)
+{
+    _parentPid = pid;
+    _fields |= PARENT_PID;
+}
+void ProcessInfo::setForegroundPid(int pid)
+{
+    _foregroundPid = pid;
+    _fields |= FOREGROUND_PID;
+}
+
+QString ProcessInfo::currentDir(bool* ok) const
+{
+    if (ok)
+        *ok = _fields & CURRENT_DIR;
+
+    return _currentDir;
+}
+void ProcessInfo::setCurrentDir(const QString& dir)
+{
+    _fields |= CURRENT_DIR;
+    _currentDir = dir;
+}
+
+void ProcessInfo::setName(const QString& name)
+{
+    _name = name;
+    _fields |= NAME;
+}
+void ProcessInfo::addArgument(const QString& argument)
+{
+    _arguments << argument;    
+}
+
+void ProcessInfo::addEnvironmentBinding(const QString& name , const QString& value)
+{
+    _environment.insert(name,value);
+}
+
+void ProcessInfo::setFileError( QFile::FileError error )
+{
+    switch ( error )
+    {
+        case PermissionsError:
+            setError( PermissionsError );
+            break;
+        case NoError:
+            setError( NoError );
+            break;
+        default:
+            setError( UnknownError );
+    }
+}
+
+//
+// ProcessInfo::newInstance() is way at the bottom so it can see all of the
+// implementations of the UnixProcessInfo abstract class.
+//
+
+NullProcessInfo::NullProcessInfo(int pid,bool enableEnvironmentRead)
+    : ProcessInfo(pid,enableEnvironmentRead)
+{
+}
+
+bool NullProcessInfo::readProcessInfo(int /*pid*/ , bool /*enableEnvironmentRead*/)
+{
+    return false;
+}
+
+void NullProcessInfo::readUserName()
+{
+}
+
+UnixProcessInfo::UnixProcessInfo(int pid,bool enableEnvironmentRead)
+    : ProcessInfo(pid,enableEnvironmentRead)
+{
+}
+
+bool UnixProcessInfo::readProcessInfo(int pid , bool enableEnvironmentRead)
+{
+    bool ok = readProcInfo(pid);
+    if (ok)
+    {
+        ok |= readArguments(pid);
+        ok |= readCurrentDir(pid);
+        if ( enableEnvironmentRead )
+        {
+            ok |= readEnvironment(pid);
+        }
+    }
+    return ok;
+}
+
+void UnixProcessInfo::readUserName()
+{
+    bool ok = false;
+    int uid = userId(&ok);
+    if (!ok) return;
+
+    struct passwd passwdStruct;
+    struct passwd *getpwResult;
+    char *getpwBuffer;
+    long getpwBufferSize;
+    int getpwStatus;
+
+    getpwBufferSize = sysconf(_SC_GETPW_R_SIZE_MAX);
+    if (getpwBufferSize == -1)
+        getpwBufferSize = 16384;
+
+    getpwBuffer = new char[getpwBufferSize];
+    if (getpwBuffer == NULL)
+        return;
+    getpwStatus = getpwuid_r(uid, &passwdStruct, getpwBuffer, getpwBufferSize, &getpwResult);
+    if (getpwResult != NULL)
+        setUserName(QString(passwdStruct.pw_name));
+    else
+        setUserName(QString());
+    delete [] getpwBuffer;
+}
+
+
+class LinuxProcessInfo : public UnixProcessInfo
+{
+public:
+    LinuxProcessInfo(int pid, bool env) :
+        UnixProcessInfo(pid,env)
+    {
+    }
+
+private:
+    virtual bool readProcInfo(int pid)
+    {
+        // indicies of various fields within the process status file which
+        // contain various information about the process
+        const int PARENT_PID_FIELD = 3;
+        const int PROCESS_NAME_FIELD = 1;
+        const int GROUP_PROCESS_FIELD = 7;
+
+        QString parentPidString;
+        QString processNameString;
+        QString foregroundPidString;
+        QString uidLine;
+        QString uidString;
+        QStringList uidStrings;
+
+        // For user id read process status file ( /proc/<pid>/status )
+        //  Can not use getuid() due to it does not work for 'su'
+        QFile statusInfo( QString("/proc/%1/status").arg(pid) );
+        if ( statusInfo.open(QIODevice::ReadOnly) )
+        {
+            QTextStream stream(&statusInfo);
+            QString statusLine;
+            do {
+                statusLine = stream.readLine(0);
+                if (statusLine.startsWith(QLatin1String("Uid:")))
+                    uidLine = statusLine;
+            } while (!statusLine.isNull() && uidLine.isNull());
+
+            uidStrings << uidLine.split('\t', QString::SkipEmptyParts);
+            // Must be 5 entries: 'Uid: %d %d %d %d' and
+            // uid string must be less than 5 chars (uint)
+            if (uidStrings.size() == 5)
+                uidString = uidStrings[1];
+            if (uidString.size() > 5)
+                uidString.clear();
+
+            bool ok = false;
+            int uid = uidString.toInt(&ok);
+            if (ok)
+                setUserId(uid);
+            readUserName();
+        }
+        else
+        {
+            setFileError( statusInfo.error() );
+            return false;
+        }
+
+
+        // read process status file ( /proc/<pid/stat )
+        //
+        // the expected file format is a list of fields separated by spaces, using
+        // parenthesies to escape fields such as the process name which may itself contain
+        // spaces:
+        //
+        // FIELD FIELD (FIELD WITH SPACES) FIELD FIELD
+        //
+        QFile processInfo( QString("/proc/%1/stat").arg(pid) );
+        if ( processInfo.open(QIODevice::ReadOnly) )
+        {
+            QTextStream stream(&processInfo);
+            QString data = stream.readAll();
+
+            int stack = 0;
+            int field = 0;
+            int pos = 0;
+
+            while (pos < data.count())
+            {
+                QChar c = data[pos];
+
+                if ( c == '(' )
+                    stack++;
+                else if ( c == ')' )
+                    stack--;
+                else if ( stack == 0 && c == ' ' )
+                    field++;
+                else
+                {
+                    switch ( field )
+                    {
+                        case PARENT_PID_FIELD:
+                            parentPidString.append(c);
+                            break;
+                        case PROCESS_NAME_FIELD:
+                            processNameString.append(c);
+                            break;
+                        case GROUP_PROCESS_FIELD:
+                            foregroundPidString.append(c);
+                            break;
+                    }
+                }
+
+                pos++;
+            }
+        }
+        else
+        {
+            setFileError( processInfo.error() );
+            return false;
+        }
+
+        // check that data was read successfully
+        bool ok = false;
+        int foregroundPid = foregroundPidString.toInt(&ok);
+        if (ok)
+            setForegroundPid(foregroundPid);
+
+        int parentPid = parentPidString.toInt(&ok);
+        if (ok)
+            setParentPid(parentPid);
+
+        if (!processNameString.isEmpty())
+            setName(processNameString);
+
+        // update object state
+        setPid(pid);
+
+        return ok;
+    }
+
+    virtual bool readArguments(int pid)
+    {
+        // read command-line arguments file found at /proc/<pid>/cmdline
+        // the expected format is a list of strings delimited by null characters,
+        // and ending in a double null character pair.
+
+        QFile argumentsFile( QString("/proc/%1/cmdline").arg(pid) );
+        if ( argumentsFile.open(QIODevice::ReadOnly) )
+        {
+            QTextStream stream(&argumentsFile);
+            QString data = stream.readAll();
+
+            QStringList argList = data.split( QChar('\0') );
+
+            foreach ( const QString &entry , argList )
+            {
+                if (!entry.isEmpty())
+                    addArgument(entry);
+            }
+        }
+        else
+        {
+            setFileError( argumentsFile.error() );
+        }
+
+        return true;
+    }
+
+    virtual bool readCurrentDir(int pid)
+    {
+        QFileInfo info( QString("/proc/%1/cwd").arg(pid) );
+
+        const bool readable = info.isReadable();
+
+        if ( readable && info.isSymLink() )
+        {
+            setCurrentDir( info.symLinkTarget() );
+            return true;
+        }
+        else
+        {
+            if ( !readable )
+                setError( PermissionsError );
+            else
+                setError( UnknownError );
+
+            return false;
+        }
+    }
+
+    virtual bool readEnvironment(int pid)
+    {
+        // read environment bindings file found at /proc/<pid>/environ
+        // the expected format is a list of KEY=VALUE strings delimited by null
+        // characters and ending in a double null character pair.
+
+        QFile environmentFile( QString("/proc/%1/environ").arg(pid) );
+        if ( environmentFile.open(QIODevice::ReadOnly) )
+        {
+            QTextStream stream(&environmentFile);
+            QString data = stream.readAll();
+
+            QStringList bindingList = data.split( QChar('\0') );
+
+            foreach( const QString &entry , bindingList )
+            {
+                QString name;
+                QString value;
+
+                int splitPos = entry.indexOf('=');
+
+                if ( splitPos != -1 )
+                {
+                    name = entry.mid(0,splitPos);
+                    value = entry.mid(splitPos+1,-1);
+
+                    addEnvironmentBinding(name,value);
+                }
+            }
+        }
+        else
+        {
+            setFileError( environmentFile.error() );
+        }
+
+        return true;
+    }
+} ;
+
+#if defined(Q_OS_FREEBSD)
+class FreeBSDProcessInfo : public UnixProcessInfo
+{
+public:
+    FreeBSDProcessInfo(int pid, bool readEnvironment) :
+        UnixProcessInfo(pid, readEnvironment)
+    {
+    }
+
+private:
+    virtual bool readProcInfo(int pid)
+    {
+        int managementInfoBase[4];
+        size_t mibLength;
+        struct kinfo_proc* kInfoProc;
+
+        managementInfoBase[0] = CTL_KERN;
+        managementInfoBase[1] = KERN_PROC;
+        managementInfoBase[2] = KERN_PROC_PID;
+        managementInfoBase[3] = pid;
+
+        if (sysctl(managementInfoBase, 4, NULL, &mibLength, NULL, 0) == -1)
+            return false;
+
+        kInfoProc = new struct kinfo_proc [mibLength];
+
+        if (sysctl(managementInfoBase, 4, kInfoProc, &mibLength, NULL, 0) == -1)
+        {
+            delete [] kInfoProc;
+            return false;
+        }
+
+#if defined(__DragonFly__)
+        setName(kInfoProc->kp_comm);
+        setPid(kInfoProc->kp_pid);
+        setParentPid(kInfoProc->kp_ppid);
+        setForegroundPid(kInfoProc->kp_pgid);
+        setUserId(kInfoProc->kp_uid);
+#else
+        setName(kInfoProc->ki_comm);
+        setPid(kInfoProc->ki_pid);
+        setParentPid(kInfoProc->ki_ppid);
+        setForegroundPid(kInfoProc->ki_pgid);
+        setUserId(kInfoProc->ki_uid);
+#endif
+
+        readUserName();
+
+        delete [] kInfoProc;
+        return true;
+    }
+
+    virtual bool readArguments(int pid)
+    {
+        char args[ARG_MAX];
+        int managementInfoBase[4];
+        size_t len;
+
+        managementInfoBase[0] = CTL_KERN;
+        managementInfoBase[1] = KERN_PROC;
+        managementInfoBase[2] = KERN_PROC_PID;
+        managementInfoBase[3] = pid;
+
+        len = sizeof(args);
+        if (sysctl(managementInfoBase, 4, args, &len, NULL, 0) == -1)
+            return false;
+
+        const QStringList argumentList = QString(args).split(QChar('\0'));
+
+        for (QStringList::const_iterator it = argumentList.begin(); it != argumentList.end(); ++it)
+        {
+            addArgument(*it);
+        }
+
+        return true;
+    }
+
+    virtual bool readEnvironment(int pid)
+    {
+        // Not supported in FreeBSD?
+        return false;
+    }
+
+    virtual bool readCurrentDir(int pid)
+    {
+#if defined(__DragonFly__)
+        char buf[PATH_MAX];
+        int managementInfoBase[4];
+        size_t len;
+
+        managementInfoBase[0] = CTL_KERN;
+        managementInfoBase[1] = KERN_PROC;
+        managementInfoBase[2] = KERN_PROC_CWD;
+        managementInfoBase[3] = pid;
+
+        len = sizeof(buf);
+        if (sysctl(managementInfoBase, 4, buf, &len, NULL, 0) == -1)
+            return false;
+
+        setCurrentDir(buf);
+
+        return true;
+#else
+        int numrecords;
+        struct kinfo_file* info = 0;
+
+        info = kinfo_getfile(pid, &numrecords);
+
+        if (!info)
+            return false;
+
+        for (int i = 0; i < numrecords; ++i)
+        {
+            if (info[i].kf_fd == KF_FD_TYPE_CWD)
+            {
+                setCurrentDir(info[i].kf_path);
+
+                free(info);
+                return true;
+            }
+        }
+
+        free(info);
+        return false;
+#endif
+    }
+} ;
+#endif
+
+#if defined(Q_OS_MAC)
+class MacProcessInfo : public UnixProcessInfo
+{
+public:
+    MacProcessInfo(int pid, bool env) :
+        UnixProcessInfo(pid, env)
+    {
+    }
+
+private:
+    virtual bool readProcInfo(int pid)
+    {
+        int managementInfoBase[4];
+        size_t mibLength;
+        struct kinfo_proc* kInfoProc;
+        KDE_struct_stat statInfo;
+
+        // Find the tty device of 'pid' (Example: /dev/ttys001)
+        managementInfoBase[0] = CTL_KERN;
+        managementInfoBase[1] = KERN_PROC;
+        managementInfoBase[2] = KERN_PROC_PID;
+        managementInfoBase[3] = pid;
+
+        if (sysctl(managementInfoBase, 4, NULL, &mibLength, NULL, 0) == -1)
+        {
+            return false;
+        } 
+        else
+        {
+            kInfoProc = new struct kinfo_proc [mibLength];
+            if (sysctl(managementInfoBase, 4, kInfoProc, &mibLength, NULL, 0) == -1)
+            {
+                delete [] kInfoProc;
+                return false;
+            }
+            else
+            { 
+                QString deviceNumber = QString(devname(((&kInfoProc->kp_eproc)->e_tdev), S_IFCHR));
+                QString fullDeviceName =  QString("/dev/") + deviceNumber.rightJustified(3, '0');
+                delete [] kInfoProc;
+
+                QByteArray deviceName = fullDeviceName.toLatin1();
+                const char* ttyName = deviceName.data();
+
+                if (KDE_stat(ttyName, &statInfo) != 0)
+                    return false;
+
+                // Find all processes attached to ttyName
+                managementInfoBase[0] = CTL_KERN;
+                managementInfoBase[1] = KERN_PROC;
+                managementInfoBase[2] = KERN_PROC_TTY;
+                managementInfoBase[3] = statInfo.st_rdev;
+
+                mibLength = 0;
+                if (sysctl(managementInfoBase, sizeof(managementInfoBase)/sizeof(int), NULL, &mibLength, NULL, 0) == -1)
+                    return false;
+
+                kInfoProc = new struct kinfo_proc [mibLength];
+                if (sysctl(managementInfoBase, sizeof(managementInfoBase)/sizeof(int), kInfoProc, &mibLength, NULL, 0) == -1)
+                    return false;
+
+                // The foreground program is the first one
+                setName(QString(kInfoProc->kp_proc.p_comm));
+
+                delete [] kInfoProc;
+            }
+        }
+        return true;
+    }
+
+    virtual bool readArguments(int pid)
+    {
+        Q_UNUSED(pid);
+        return false;
+    }
+    virtual bool readCurrentDir(int pid)
+    {
+        struct proc_vnodepathinfo vpi;
+        int nb = proc_pidinfo(pid, PROC_PIDVNODEPATHINFO, 0, &vpi, sizeof(vpi));
+        if (nb == sizeof(vpi))
+        {
+            setCurrentDir(QString(vpi.pvi_cdir.vip_path));
+            return true;
+        }
+        return false;
+    }
+    virtual bool readEnvironment(int pid)
+    {
+        Q_UNUSED(pid);
+        return false;
+    }
+} ;
+#endif
+
+#ifdef Q_OS_SOLARIS
+    // The procfs structure definition requires off_t to be
+    // 32 bits, which only applies if FILE_OFFSET_BITS=32.
+    // Futz around here to get it to compile regardless,
+    // although some of the structure sizes might be wrong.
+    // Fortunately, the structures we actually use don't use
+    // off_t, and we're safe.
+    #if defined(_FILE_OFFSET_BITS) && (_FILE_OFFSET_BITS==64)
+        #undef _FILE_OFFSET_BITS
+    #endif
+    #include <procfs.h>
+#else
+    // On non-Solaris platforms, define a fake psinfo structure
+    // so that the SolarisProcessInfo class can be compiled
+    //
+    // That avoids the trap where you change the API and
+    // don't notice it in #ifdeffed platform-specific parts
+    // of the code.
+    struct psinfo {
+        int pr_ppid;
+        int pr_pgid;
+        char* pr_fname;
+        char* pr_psargs;
+    } ;
+    static const int PRARGSZ=1;
+#endif
+
+class SolarisProcessInfo : public UnixProcessInfo
+{
+public:
+    SolarisProcessInfo(int pid, bool readEnvironment) 
+    : UnixProcessInfo(pid,readEnvironment)
+    {
+    }
+private:
+    virtual bool readProcInfo(int pid)
+    {
+        QFile psinfo( QString("/proc/%1/psinfo").arg(pid) );
+        if ( psinfo.open( QIODevice::ReadOnly ) )
+        {
+            struct psinfo info;
+            if (psinfo.read((char *)&info,sizeof(info)) != sizeof(info))
+            {
+                return false;
+            }
+
+            setParentPid(info.pr_ppid);
+            setForegroundPid(info.pr_pgid);
+            setName(info.pr_fname);
+            setPid(pid);
+
+            // Bogus, because we're treating the arguments as one single string
+            info.pr_psargs[PRARGSZ-1]=0;
+            addArgument(info.pr_psargs);
+        }
+        return true;
+    }
+
+    virtual bool readArguments(int /*pid*/)
+    {
+        // Handled in readProcInfo()
+        return false;
+    }
+
+    virtual bool readEnvironment(int /*pid*/)
+    {
+        // Not supported in Solaris
+        return false;
+    }
+
+    virtual bool readCurrentDir(int pid)
+    {
+        QFileInfo info( QString("/proc/%1/path/cwd").arg(pid) );
+        const bool readable = info.isReadable();
+
+        if ( readable && info.isSymLink() )
+        {
+            setCurrentDir( info.symLinkTarget() );
+            return true;
+        }
+        else
+        {
+            if ( !readable )
+                setError( PermissionsError );
+            else
+                setError( UnknownError );
+
+            return false;
+        }
+    }
+} ;
+
+SSHProcessInfo::SSHProcessInfo(const ProcessInfo& process)
+ : _process(process)
+{
+    bool ok = false;
+
+    // check that this is a SSH process
+    const QString& name = _process.name(&ok);
+
+    if ( !ok || name != "ssh" )
+    {
+        //if ( !ok )
+        //    kWarning() << "Could not read process info";
+        //else
+        //    kWarning() << "Process is not a SSH process";
+
+        return;
+    }
+
+    // read arguments
+    const QVector<QString>& args = _process.arguments(&ok); 
+
+    // SSH options
+    // these are taken from the SSH manual ( accessed via 'man ssh' )
+    
+    // options which take no arguments
+    static const QString noOptionsArguments("1246AaCfgkMNnqsTtVvXxY"); 
+    // options which take one argument
+    static const QString singleOptionArguments("bcDeFiLlmOopRSw");
+
+    if ( ok )
+    {
+         // find the username, host and command arguments
+         //
+         // the username/host is assumed to be the first argument 
+         // which is not an option
+         // ( ie. does not start with a dash '-' character )
+         // or an argument to a previous option.
+         //
+         // the command, if specified, is assumed to be the argument following
+         // the username and host
+         //
+         // note that we skip the argument at index 0 because that is the
+         // program name ( expected to be 'ssh' in this case )
+         for ( int i = 1 ; i < args.count() ; i++ )
+         {
+            // if this argument is an option then skip it, plus any 
+            // following arguments which refer to this option
+            if ( args[i].startsWith('-') )
+            {
+                QChar argChar = ( args[i].length() > 1 ) ? args[i][1] : '\0';
+
+                if ( noOptionsArguments.contains(argChar) )
+                    continue;
+                else if ( singleOptionArguments.contains(argChar) )
+                {
+                    i++;
+                    continue;
+                }
+            }
+
+            // check whether the host has been found yet
+            // if not, this must be the username/host argument 
+            if ( _host.isEmpty() )
+            {
+                // check to see if only a hostname is specified, or whether
+                // both a username and host are specified ( in which case they
+                // are separated by an '@' character:  username@host )
+            
+                int separatorPosition = args[i].indexOf('@');
+                if ( separatorPosition != -1 )
+                {
+                    // username and host specified
+                    _user = args[i].left(separatorPosition);
+                    _host = args[i].mid(separatorPosition+1);
+                }
+                else
+                {
+                    // just the host specified
+                    _host = args[i];
+                }
+            }
+            else
+            {
+                // host has already been found, this must be the command argument
+                _command = args[i];
+            }
+
+         }
+    }
+    else
+    {
+        //kWarning() << "Could not read arguments";
+        
+        return;
+    }
+}
+
+QString SSHProcessInfo::userName() const
+{
+    return _user;
+}
+QString SSHProcessInfo::host() const
+{
+    return _host;
+}
+QString SSHProcessInfo::command() const
+{
+    return _command;
+}
+QString SSHProcessInfo::format(const QString& input) const
+{
+    QString output(input);
+   
+    // test whether host is an ip address
+    // in which case 'short host' and 'full host'
+    // markers in the input string are replaced with
+    // the full address
+    bool isIpAddress = false;
+   
+    struct in_addr address;
+    if ( inet_aton(_host.toLocal8Bit().constData(),&address) != 0 )
+        isIpAddress = true;
+    else
+        isIpAddress = false;
+
+    // search for and replace known markers
+    output.replace("%u",_user);
+
+    if ( isIpAddress )
+        output.replace("%h",_host);
+    else
+        output.replace("%h",_host.left(_host.indexOf('.')));
+    
+    output.replace("%H",_host);
+    output.replace("%c",_command);
+
+    return output;
+}
+
+ProcessInfo* ProcessInfo::newInstance(int pid,bool enableEnvironmentRead)
+{
+#ifdef Q_OS_LINUX
+    return new LinuxProcessInfo(pid,enableEnvironmentRead);
+#elif defined(Q_OS_SOLARIS)
+    return new SolarisProcessInfo(pid,enableEnvironmentRead);
+#elif defined(Q_OS_MAC)
+    return new MacProcessInfo(pid,enableEnvironmentRead);
+#elif defined(Q_OS_FREEBSD)
+    return new FreeBSDProcessInfo(pid,enableEnvironmentRead);
+#else
+    return new NullProcessInfo(pid,enableEnvironmentRead);
+#endif
+}
+
new file mode 100644
--- /dev/null
+++ b/gui/src/ProcessInfo.h
@@ -0,0 +1,454 @@
+/*
+    Copyright 2007-2008 by Robert Knight <robertknight@gmail.com>
+
+    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 PROCESSINFO_H
+#define PROCESSINFO_H
+
+// Qt
+#include <QtCore/QFile>
+#include <QtCore/QMap>
+#include <QtCore/QString>
+#include <QtCore/QVector>
+
+/**
+ * Takes a snapshot of the state of a process and provides access to 
+ * information such as the process name, parent process,
+ * the foreground process in the controlling terminal,
+ * the arguments with which the process was started and the 
+ * environment.
+ *
+ * To create a new snapshot, construct a new ProcessInfo instance,
+ * using ProcessInfo::newInstance(),
+ * passing the process identifier of the process you are interested in.
+ *
+ * After creating a new instance, call the update() method to take a 
+ * snapshot of the current state of the process.
+ *
+ * Before calling any additional methods, check that the process state
+ * was read successfully using the isValid() method.
+ *
+ * Each accessor method which provides information about the process state ( such as pid(), 
+ * currentDir(), name() ) takes a pointer to a boolean as an argument.  If the information
+ * requested was read successfully then the boolean is set to true, otherwise it is set
+ * to false, in which case the return value from the function should be ignored.
+ * If this boolean is set to false, it may indicate an error reading the process information,
+ * or it may indicate that the information is not available on the current platform. 
+ *
+ * eg.
+ *
+ * @code
+ *   ProcessInfo* info = ProcessInfo::newInstance(pid);
+ *   info->update();
+ *
+ *   if ( info->isValid() )
+ *   {
+ *      bool ok;
+ *      QString value = info->name(&ok);
+ *
+ *      if ( ok ) kDebug() << "process name - " << name;
+ *      int parentPid = info->parentPid(&ok);
+ *      if ( ok ) kDebug() << "parent process - " << parentPid;
+ *      int foregroundPid = info->foregroundColororegroundPid(&ok);
+ *      if ( ok ) kDebug() << "foreground process - " << foregroundPid;
+ *   }
+ * @endcode
+ */
+class ProcessInfo
+{
+public:
+    /**
+     * Constructs a new instance of a suitable ProcessInfo sub-class for 
+     * the current platform which provides information about a given process.
+     *
+     * @param pid The pid of the process to examine
+     * @param readEnvironment Specifies whether environment bindings should
+     * be read.  If this is false, then environment() calls will
+     * always fail.  This is an optimization to avoid the overhead
+     * of reading the (potentially large) environment data when it
+     * is not required. 
+     */
+    static ProcessInfo* newInstance(int pid,bool readEnvironment = false);
+
+    virtual ~ProcessInfo() {}
+
+    /** 
+     * Updates the information about the process.  This must
+     * be called before attempting to use any of the accessor methods.
+     */
+    void update();
+
+    /** Returns true if the process state was read successfully. */ 
+    bool isValid() const;
+    /** 
+     * Returns the process id.  
+     *
+     * @param ok Set to true if the process id was read successfully or false otherwise 
+     */
+    int pid(bool* ok) const;
+    /** 
+     * Returns the id of the parent process id was read successfully or false otherwise
+     * 
+     * @param ok Set to true if the parent process id
+     */
+    int parentPid(bool* ok) const;
+    
+    /** 
+     * Returns the id of the current foreground process 
+     *
+     * NOTE:  Using the foregroundProcessGroup() method of the Pty
+     * instance associated with the terminal of interest is preferred
+     * over using this method.
+     *
+     * @param ok Set to true if the foreground process id was read successfully or false otherwise
+     */
+    int foregroundPid(bool* ok) const;
+    
+    /* Returns the user id of the process */
+    int userId(bool* ok) const;
+
+    /** Returns the user's name of the process */
+    QString userName() const;
+   
+    /** Returns the user's home directory of the process */
+    QString userHomeDir() const;
+
+    /** Returns the name of the current process */
+    QString name(bool* ok) const;
+   
+    /** 
+     * Returns the command-line arguments which the process
+     * was started with.
+     *
+     * The first argument is the name used to launch the process.
+     *
+     * @param ok Set to true if the arguments were read successfully or false otherwise.
+     */
+    QVector<QString> arguments(bool* ok) const;
+    /**
+     * Returns the environment bindings which the process
+     * was started with.
+     * In the returned map, the key is the name of the environment variable,
+     * and the value is the corresponding value.
+     *
+     * @param ok Set to true if the environment bindings were read successfully or false otherwise
+     */
+    QMap<QString,QString> environment(bool* ok) const;
+
+    /**
+     * Returns the current working directory of the process
+     *
+     * @param ok Set to true if the current working directory was read successfully or false otherwise
+     */
+    QString currentDir(bool* ok) const;
+
+    /**
+     * Returns the current working directory of the process (or its parent)
+     */
+    QString validCurrentDir() const;
+
+    /** Forces the user home directory to be calculated */
+    void setUserHomeDir();
+
+    /**
+     * Parses an input string, looking for markers beginning with a '%' 
+     * character and returns a string with the markers replaced
+     * with information from this process description.
+     * <br>
+     * The markers recognised are:
+     * <ul>
+     * <li> %u - Name of the user which owns the process. </li>
+     * <li> %n - Replaced with the name of the process.   </li>
+     * <li> %d - Replaced with the last part of the path name of the 
+     *      process' current working directory.
+     *      
+     *      (eg. if the current directory is '/home/bob' then
+     *      'bob' would be returned)
+     * </li>
+     * <li> %D - Replaced with the current working directory of the process. </li>
+     * </ul>
+     */
+    QString format(const QString& text) const;
+
+    /** 
+     * This enum describes the errors which can occur when trying to read 
+     * a process's information.
+     */
+    enum Error
+    {
+        /** No error occurred. */
+        NoError,
+        /** The nature of the error is unknown. */
+        UnknownError,
+        /** Konsole does not have permission to obtain the process information. */
+        PermissionsError
+    };
+
+    /**
+     * Returns the last error which occurred.
+     */
+    Error error() const;
+
+protected:
+    /**
+     * Constructs a new process instance.  You should not call the constructor
+     * of ProcessInfo or its subclasses directly.  Instead use the 
+     * static ProcessInfo::newInstance() method which will return
+     * a suitable ProcessInfo instance for the current platform.
+     */ 
+    explicit ProcessInfo(int pid , bool readEnvironment = false);
+
+    /** 
+     * This is called on construction to read the process state 
+     * Subclasses should reimplement this function to provide
+     * platform-specific process state reading functionality.
+     *
+     * When called, readProcessInfo() should attempt to read all
+     * of the necessary state information.  If the attempt is successful,
+     * it should set the process id using setPid(), and update
+     * the other relevant information using setParentPid(), setName(),
+     * setArguments() etc.
+     *
+     * Calls to isValid() will return true only if the process id
+     * has been set using setPid()
+     *
+     * @param pid The process id of the process to read
+     * @param readEnvironment Specifies whether the environment bindings
+     *                        for the process should be read
+     */
+    virtual bool readProcessInfo(int pid , bool readEnvironment) = 0;
+
+    /* Read the user name */
+    virtual void readUserName(void) = 0;
+
+    /** Sets the process id associated with this ProcessInfo instance */
+    void setPid(int pid);
+    /** Sets the parent process id as returned by parentPid() */
+    void setParentPid(int pid);
+    /** Sets the foreground process id as returend by foregroundPid() */
+    void setForegroundPid(int pid);
+    /** Sets the user id associated with this ProcessInfo instance */
+    void setUserId(int uid);
+    /** Sets the user name of the process as set by readUserName() */
+    void setUserName(const QString& name);
+    /** Sets the name of the process as returned by name() */
+    void setName(const QString& name);
+    /** Sets the current working directory for the process */
+    void setCurrentDir(const QString& dir);
+
+    /** Sets the error */
+    void setError( Error error );
+
+    /** Convenience method.  Sets the error based on a QFile error code. */ 
+    void setFileError( QFile::FileError error ); 
+
+    /** 
+     * Adds a commandline argument for the process, as returned
+     * by arguments()
+     */
+    void addArgument(const QString& argument);
+    /**
+     * Adds an environment binding for the process, as returned by
+     * environment()
+     *
+     * @param name The name of the environment variable, eg. "PATH"
+     * @param value The value of the environment variable, eg. "/bin"
+     */
+    void addEnvironmentBinding(const QString& name , const QString& value);
+
+private:
+    enum CommandFormat
+    {
+        ShortCommandFormat,
+        LongCommandFormat
+    };
+    // takes a process name and its arguments and produces formatted output
+    QString formatCommand(const QString& name , const QVector<QString>& arguments , 
+                          CommandFormat format) const;
+
+    // valid bits for _fields variable, ensure that
+    // _fields is changed to an int if more than 8 fields are added
+    enum FIELD_BITS
+    {
+        PROCESS_ID          = 1,
+        PARENT_PID          = 2,
+        FOREGROUND_PID      = 4,
+        ARGUMENTS           = 8,
+        ENVIRONMENT         = 16,
+        NAME                = 32,
+        CURRENT_DIR         = 64,
+        UID                 =128 
+    };
+
+    char _fields; // a bitmap indicating which fields are valid
+                  // used to set the "ok" parameters for the public
+                  // accessor functions
+
+    bool _enableEnvironmentRead; // specifies whether to read the environment
+                                 // bindings when update() is called
+    int _pid;  
+    int _parentPid;
+    int _foregroundPid;
+    int _userId;  
+
+    Error _lastError;
+
+    QString _name;
+    QString _userName;
+    QString _userHomeDir;
+    QString _currentDir;
+
+    QVector<QString> _arguments;
+    QMap<QString,QString> _environment;
+};
+
+/** 
+ * Implementation of ProcessInfo which does nothing.
+ * Used on platforms where a suitable ProcessInfo subclass is not 
+ * available.
+ *
+ * isValid() will always return false for instances of NullProcessInfo
+ */
+class NullProcessInfo : public ProcessInfo
+{
+public:
+    /** 
+     * Constructs a new NullProcessInfo instance.
+     * See ProcessInfo::newInstance()
+     */
+    explicit NullProcessInfo(int pid,bool readEnvironment = false);
+protected:
+    virtual bool readProcessInfo(int pid,bool readEnvironment);
+    virtual void readUserName(void);
+};
+
+/**
+ * Implementation of ProcessInfo for Unix platforms which uses
+ * the /proc filesystem
+ */
+class UnixProcessInfo : public ProcessInfo
+{
+public:
+    /** 
+     * Constructs a new instance of UnixProcessInfo.
+     * See ProcessInfo::newInstance()
+     */
+    explicit UnixProcessInfo(int pid,bool readEnvironment = false);
+
+protected:
+    /** 
+     * Implementation of ProcessInfo::readProcessInfo(); calls the
+     * four private methods below in turn.
+     */
+    virtual bool readProcessInfo(int pid , bool readEnvironment);
+
+    virtual void readUserName(void);
+
+private:
+    /**
+     * Read the standard process information -- PID, parent PID, foreground PID.
+     * @param pid process ID to use
+     * @return true on success
+     */
+    virtual bool readProcInfo(int pid)=0;
+
+    /**
+     * Read the environment of the process. Sets _environment.
+     * @param pid process ID to use
+     * @return true on success
+     */
+    virtual bool readEnvironment(int pid)=0;
+
+    /**
+     * Determine what arguments were passed to the process. Sets _arguments.
+     * @param pid process ID to use
+     * @return true on success
+     */
+    virtual bool readArguments(int pid)=0;
+
+    /**
+     * Determine the current directory of the process.
+     * @param pid process ID to use
+     * @return true on success
+     */
+    virtual bool readCurrentDir(int pid)=0;
+};
+
+/** 
+ * Lightweight class which provides additional information about SSH processes.
+ */
+class SSHProcessInfo
+{
+public:
+    /** 
+     * Constructs a new SSHProcessInfo instance which provides additional
+     * information about the specified SSH process.
+     *
+     * @param process A ProcessInfo instance for a SSH process.
+     */
+    SSHProcessInfo(const ProcessInfo& process);
+
+    /** 
+     * Returns the user name which the user initially logged into on
+     * the remote computer.
+     */
+    QString userName() const;
+
+    /**
+     * Returns the host which the user has connected to.
+     */
+    QString host() const;
+
+    /** 
+     * Returns the command which the user specified to execute on the 
+     * remote computer when starting the SSH process.
+     */
+    QString command() const;
+
+    /**
+     * Operates in the same way as ProcessInfo::format(), except
+     * that the set of markers understood is different:
+     *
+     * %u - Replaced with user name which the user initially logged
+     *      into on the remote computer.
+     * %h - Replaced with the first part of the host name which
+     *      is connected to.
+     * %H - Replaced with the full host name of the computer which
+     *      is connected to.
+     * %c - Replaced with the command which the user specified
+     *      to execute when starting the SSH process.
+     */
+    QString format(const QString& input) const;
+
+private:
+    const ProcessInfo& _process;
+    QString _user;
+    QString _host;
+    QString _command;
+};
+
+#endif //PROCESSINFO_H
+
+/*
+  Local Variables:
+  mode: c++
+  c-file-style: "stroustrup"
+  indent-tabs-mode: nil
+  tab-width: 4
+  End:
+*/
new file mode 100644
--- /dev/null
+++ b/gui/src/Pty.cpp
@@ -0,0 +1,310 @@
+/*
+    This file is part of Konsole, an X terminal.
+    Copyright 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
+
+    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 "kprocess_p.h"
+#include "kptyprocess.h"
+#include "Pty.h"
+
+// System
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+#include <termios.h>
+#include <signal.h>
+
+// Qt
+#include <QtCore/QStringList>
+
+#include "kpty.h"
+#include "kptydevice.h"
+
+
+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::setFlowControlEnabled(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))
+    //  kWarning() << "Unable to set terminal attributes.";
+  }
+}
+bool Pty::flowControlEnabled() const
+{
+    if (pty()->masterFd() >= 0)
+    {
+        struct ::termios ttmode;
+        pty()->tcGetAttr(&ttmode);
+        return ttmode.c_iflag & IXOFF &&
+               ttmode.c_iflag & IXON;
+    }  
+    //kWarning() << "Unable to get flow control status, terminal not connected.";
+    return false;
+}
+
+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))
+    //  kWarning() << "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))
+    //  kWarning() << "Unable to set terminal attributes.";
+  }
+}
+
+char Pty::erase() const
+{
+    if (pty()->masterFd() >= 0)
+    {
+        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);
+
+            setEnv(variable,value);
+        }
+    }
+}
+
+int Pty::start(const QString& program, 
+               const QStringList& programArguments, 
+               const QStringList& environment, 
+               ulong winid, 
+               bool addToUtmp,
+               const QString& dbusService, 
+               const QString& dbusSession)
+{
+  clearProgram();
+
+  // For historical reasons, the first argument in programArguments is the 
+  // name of the program to execute, so create a list consisting of all
+  // but the first argument to pass to setProgram()
+  Q_ASSERT(programArguments.count() >= 1);
+  setProgram(program.toLatin1(),programArguments.mid(1));
+
+  addEnvironmentVariables(environment);
+
+  if ( !dbusService.isEmpty() )
+     setEnv("KONSOLE_DBUS_SERVICE",dbusService);
+  if ( !dbusSession.isEmpty() )
+     setEnv("KONSOLE_DBUS_SESSION", dbusSession);
+
+  setEnv("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 messages in the wrong language
+  //
+  // this can happen if LANG contains a language which KDE
+  // does not have a translation for
+  //
+  // BR:149300
+  setEnv("LANGUAGE",QString(),false /* do not overwrite existing value if any */);
+
+  setUseUtmp(addToUtmp);
+
+  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))
+  //  kWarning() << "Unable to set terminal attributes.";
+  
+  pty()->setWinSize(_windowLines, _windowColumns);
+
+  KProcess::start();
+
+  if (!waitForStarted())
+      return -1;
+
+  return 0;
+}
+
+void Pty::setWriteable(bool writeable)
+{
+  //KDE_struct_stat sbuf;
+  struct stat sbuf;
+  //KDE_stat(pty()->ttyName(), &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(int masterFd, QObject* parent)
+    : KPtyProcess(masterFd,parent)
+{
+    init();
+}
+Pty::Pty(QObject* parent)
+    : KPtyProcess(parent)
+{
+    init();
+}
+void Pty::init()
+{
+  _windowColumns = 0;
+  _windowLines = 0;
+  _eraseChar = 0;
+  _xonXoff = true;
+  _utf8 =true;
+
+  connect(pty(), SIGNAL(readyRead()) , this , SLOT(dataReceived()));
+  setPtyChannels(KPtyProcess::AllChannels);
+}
+
+Pty::~Pty()
+{
+}
+
+void Pty::sendData(const char* data, int length)
+{
+  if (!length)
+      return;
+  
+  if (!pty()->write(data,length)) 
+  {
+    //kWarning() << "Pty::doSendJobs - Could not send input data to terminal process.";
+    return;
+  }
+}
+
+void Pty::dataReceived() 
+{
+     QByteArray data = pty()->readAll();
+    emit receivedData(data.constData(),data.count());
+}
+
+void Pty::lockPty(bool lock)
+{
+    Q_UNUSED(lock);
+
+// TODO: Support for locking the Pty
+  //if (lock)
+    //suspend();
+  //else
+    //resume();
+}
+
+int Pty::foregroundProcessGroup() const
+{
+    int pid = tcgetpgrp(pty()->masterFd());
+
+    if ( pid != -1 )
+    {
+        return pid;
+    } 
+
+    return 0;
+}
+
+void Pty::setupChildProcess()
+{
+    KPtyProcess::setupChildProcess();
+    
+    // reset all signal handlers
+    // this ensures that terminal applications respond to 
+    // signals generated via key sequences such as Ctrl+C
+    // (which sends SIGINT)
+    struct sigaction action;
+    sigemptyset(&action.sa_mask);
+    action.sa_handler = SIG_DFL;
+    action.sa_flags = 0;
+    for (int signal=1;signal < NSIG; signal++)
+        sigaction(signal,&action,0L);
+}
new file mode 100644
--- /dev/null
+++ b/gui/src/Pty.h
@@ -0,0 +1,201 @@
+/*
+    This file is part of Konsole, KDE's terminal emulator. 
+    
+    Copyright 2007-2008 by Robert Knight <robertknight@gmail.com>
+    Copyright 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
+
+    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/QSize>
+
+// KDE
+#include "kprocess.h"
+#include "kptyprocess.h"
+
+/**
+ * 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 KONSOLEPRIVATE_EXPORT Pty: public KPtyProcess
+class Pty: public KPtyProcess
+{
+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.
+     */
+    explicit Pty(QObject* parent = 0);
+
+    /** 
+     * Construct a process using an open pty master.
+     * See KPtyProcess::KPtyProcess()
+     */
+    explicit Pty(int ptyMasterFd, QObject* parent = 0);
+
+    ~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.  The flow control setting
+     * may be changed later by a terminal application, so flowControlEnabled()
+     * may not equal the value of @p on in the previous call to setFlowControlEnabled()
+     */
+    void setFlowControlEnabled(bool on);
+
+    /** Queries the terminal state and returns true if Xon/Xoff flow control is enabled. */
+    bool flowControlEnabled() const;
+
+    /** 
+     * 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;
+   
+  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 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);
+   
+  protected:
+      void setupChildProcess();
+
+  private slots:
+    // called when data is received from the terminal process 
+    void dataReceived(); 
+    
+  private:
+      void init();
+
+    // takes a list of key=value pairs and adds them
+    // to the environment for the process
+    void addEnvironmentVariables(const QStringList& environment);
+
+    int  _windowColumns; 
+    int  _windowLines;
+    char _eraseChar;
+    bool _xonXoff;
+    bool _utf8;
+};
+
+#endif // PTY_H
new file mode 100644
--- /dev/null
+++ b/gui/src/QTerminalWidget.cpp
@@ -0,0 +1,191 @@
+/*  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 "QTerminalWidget.h"
+#include "Session.h"
+#include "TerminalDisplay.h"
+
+struct TermWidgetImpl
+{
+    TermWidgetImpl(QWidget* parent = 0);
+
+    TerminalDisplay *m_terminalDisplay;
+    Session *m_session;
+    Session* createSession();
+    TerminalDisplay* createTerminalDisplay(Session *session, QWidget* parent);
+};
+
+TermWidgetImpl::TermWidgetImpl(QWidget* parent)
+{
+    QPalette palette = QApplication::palette();
+    m_session = createSession();
+    m_terminalDisplay = createTerminalDisplay(this->m_session, parent);
+    m_terminalDisplay->setBackgroundColor(palette.color(QPalette::Base));
+    m_terminalDisplay->setForegroundColor(palette.color(QPalette::Text));
+}
+
+Session *TermWidgetImpl::createSession()
+{
+    Session *session = new Session();
+    session->setTitle(Session::NameRole, "QTerminalWidget");
+    session->setProgram("/bin/bash");
+    session->setArguments(QStringList());
+    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(parent);
+    display->setBellMode(TerminalDisplay::NotifyBell);
+    display->setTerminalSizeHint(true);
+    display->setTripleClickMode(TerminalDisplay::SelectWholeLine);
+    display->setTerminalSizeStartup(true);
+    display->setRandomSeed(session->sessionId() * 31);
+    return display;
+}
+
+QTerminalWidget::QTerminalWidget(int startnow, QWidget *parent)
+    :QWidget(parent)
+{
+    m_impl = new TermWidgetImpl(this);
+    
+    initialize();
+
+    if(startnow && m_impl->m_session) {
+	m_impl->m_session->run();
+    }
+
+    setFocus(Qt::OtherFocusReason);
+    m_impl->m_terminalDisplay->resize(this->size());
+    setFocusProxy(m_impl->m_terminalDisplay);
+}
+
+void QTerminalWidget::startShellProgram()
+{
+    if(m_impl->m_session->isRunning())
+	return;
+	
+    m_impl->m_session->run();
+}
+
+void QTerminalWidget::initialize()
+{    
+    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()));
+}
+
+QTerminalWidget::~QTerminalWidget()
+{
+    emit destroyed();
+}
+
+void QTerminalWidget::setTerminalFont(QFont &font)
+{
+    if (!m_impl->m_terminalDisplay)
+	return;
+    m_impl->m_terminalDisplay->setVTFont(font);
+}
+
+void QTerminalWidget::setShellProgram(QString progname)
+{
+    if (!m_impl->m_session)
+	return;
+    m_impl->m_session->setProgram(progname);	
+}
+
+void QTerminalWidget::openTeletype(int fd)
+{
+  if ( m_impl->m_session->isRunning() )
+    return;
+
+  m_impl->m_session->openTeletype(fd);
+}
+
+void QTerminalWidget::setArgs(QStringList &args)
+{
+    if (!m_impl->m_session)
+	return;
+    m_impl->m_session->setArguments(args);	
+}
+
+void QTerminalWidget::setTextCodec(QTextCodec *codec)
+{
+    if (!m_impl->m_session)
+	return;
+    m_impl->m_session->setCodec(codec);	
+}
+
+void QTerminalWidget::setSize(int h, int v)
+{
+    if (!m_impl->m_terminalDisplay)
+	return;
+    m_impl->m_terminalDisplay->setSize(h, v);
+}
+
+void QTerminalWidget::setHistorySize(int lines)
+{
+    if (lines < 0)
+        m_impl->m_session->setHistoryType(HistoryTypeFile());
+    else
+	m_impl->m_session->setHistoryType(HistoryTypeBuffer(lines));
+}
+
+void QTerminalWidget::setScrollBarPosition(ScrollBarPosition pos)
+{
+    if (!m_impl->m_terminalDisplay)
+	return;
+    m_impl->m_terminalDisplay->setScrollBarPosition((TerminalDisplay::ScrollBarPosition)pos);
+}
+
+void QTerminalWidget::sendText(const QString &text)
+{
+    m_impl->m_session->sendText(text); 
+}
+
+void QTerminalWidget::installEventFilterOnDisplay(QObject *object) {
+    m_impl->m_terminalDisplay->installEventFilter(object);
+}
+
+void QTerminalWidget::resizeEvent(QResizeEvent*)
+{
+    m_impl->m_terminalDisplay->resize(this->size());
+    m_impl->m_terminalDisplay->update();
+}
+
+void QTerminalWidget::sessionFinished()
+{
+    emit finished();
+}
+
+
new file mode 100644
--- /dev/null
+++ b/gui/src/QTerminalWidget.h
@@ -0,0 +1,93 @@
+/*  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 QTERMINALWIDGET_H
+#define QTERMINALWIDGET_H
+
+#include <QtGui>
+
+struct TermWidgetImpl;
+/**
+  * \class QTerminalWidget
+  * This class forms a widget class that can be inserted into other widgets.
+  */
+class QTerminalWidget : public QWidget
+{
+    Q_OBJECT
+public:
+    /**
+      * \enum ScrollBarPosition
+      * Defines the scrollbar position of the terminal.
+      */
+    enum ScrollBarPosition
+    {
+        NoScrollBar,
+        ScrollBarLeft,
+        ScrollBarRight
+    };
+
+    QTerminalWidget(int startnow = 1, QWidget *parent = 0);
+    ~QTerminalWidget();
+
+    void startShellProgram();
+    void openTeletype(int fd);
+
+    /** 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);
+    
+    /** Resize terminal widget. */
+    void setSize(int h, int v);
+    
+    /** History size for scrolling, values below zero mean infinite. */
+    void setHistorySize(int lines);
+
+    /** Presence of scrollbar. By default, there is no scrollbar present. */
+    void setScrollBarPosition(ScrollBarPosition);
+    
+    /** Send some text to the terminal. */
+    void sendText(const QString &text);
+
+    /** Installs an event filter onto the display. */
+    void installEventFilterOnDisplay(QObject *object);
+            
+signals:
+    /** Emitted, when the current program has finished. */
+    void finished();
+        
+protected: 
+    virtual void resizeEvent(QResizeEvent *);
+    
+protected slots:
+    void sessionFinished();        
+    
+private:
+    /** Performs initial operations on this widget. */
+    void initialize();
+    TermWidgetImpl *m_impl;
+};
+
+#endif // QTERMINALWIDGET_H
new file mode 100644
--- /dev/null
+++ b/gui/src/Quint.cpp
@@ -0,0 +1,41 @@
+/* Quint - A graphical user interface for Octave
+ * Copyright (C) 2011 Jacob Dawid
+ * jacob.dawid@googlemail.com
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <QtGui/QApplication>
+#include <QTranslator>
+#include <QSettings>
+#include "MainWindow.h"
+
+int main(int argc, char *argv[])
+{
+    QApplication application(argc, argv);
+
+    QDesktopServices desktopServices;
+    QSettings settings(
+                desktopServices.storageLocation(QDesktopServices::HomeLocation)
+                + "/.quint/settings.ini", QSettings::IniFormat);
+
+    QTranslator translator;
+    translator.load(QString("../languages/%1.qm").arg(settings.value("application/language").toString()));
+    application.installTranslator(&translator);
+
+    MainWindow w;
+    w.show();
+
+    return application.exec();
+}
new file mode 100644
--- /dev/null
+++ b/gui/src/Screen.cpp
@@ -0,0 +1,1356 @@
+/*
+   This file is part of Konsole, an X terminal.
+
+   Copyright 2007-2008 by Robert Knight <robert.knight@gmail.com>
+   Copyright 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
+
+   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"
+
+//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),
+    history(new HistoryScrollNone()),
+    cuX(0), cuY(0),
+    currentRendition(0),
+    _topMargin(0), _bottomMargin(0),
+    selBegin(0), selTopLeft(0), selBottomRight(0),
+    blockSelectionMode(false),
+    effectiveForeground(CharacterColor()), effectiveBackground(CharacterColor()), effectiveRendition(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 history;
+}
+
+void Screen::cursorUp(int n)
+    //=CUU
+{
+    if (n == 0) n = 1; // Default
+    int stop = cuY < _topMargin ? 0 : _topMargin;
+    cuX = qMin(columns-1,cuX); // nowrap!
+    cuY = qMax(stop,cuY-n);
+}
+
+void Screen::cursorDown(int n)
+    //=CUD
+{
+    if (n == 0) n = 1; // Default
+    int stop = cuY > _bottomMargin ? lines-1 : _bottomMargin;
+    cuX = qMin(columns-1,cuX); // nowrap!
+    cuY = qMin(stop,cuY+n);
+}
+
+void Screen::cursorLeft(int n)
+    //=CUB
+{
+    if (n == 0) n = 1; // Default
+    cuX = qMin(columns-1,cuX); // nowrap!
+    cuX = qMax(0,cuX-n);
+}
+
+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 ) )
+    { //Debug()<<" setRegion("<<top<<","<<bot<<") : bad range.";
+        return;                   // Default error action: ignore
+    }
+    _topMargin = top;
+    _bottomMargin = bot;
+    cuX = 0;
+    cuY = getMode(MODE_Origin) ? top : 0;
+
+}
+
+int Screen::topMargin() const
+{
+    return _topMargin;
+}
+int Screen::bottomMargin() const
+{
+    return _bottomMargin;
+}
+
+void Screen::index()
+    //=IND
+{
+    if (cuY == _bottomMargin)
+        scrollUp(1);
+    else if (cuY < lines-1)
+        cuY += 1;
+}
+
+void Screen::reverseIndex()
+    //=RI
+{
+    if (cuY == _topMargin)
+        scrollDown(_topMargin,1);
+    else if (cuY > 0)
+        cuY -= 1;
+}
+
+void Screen::nextLine()
+    //=NEL
+{
+    toStartOfLine(); 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() - 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);
+}
+
+void Screen::insertLines(int n)
+{
+    if (n == 0) n = 1; // Default
+    scrollDown(cuY,n);
+}
+
+void Screen::setMode(int m)
+{
+    currentModes[m] = true;
+    switch(m)
+    {
+        case MODE_Origin : cuX = 0; cuY = _topMargin; break; //FIXME: home
+    }
+}
+
+void Screen::resetMode(int m)
+{
+    currentModes[m] = false;
+    switch(m)
+    {
+        case MODE_Origin : cuX = 0; cuY = 0; break; //FIXME: home
+    }
+}
+
+void Screen::saveMode(int m)
+{
+    savedModes[m] = currentModes[m];
+}
+
+void Screen::restoreMode(int m)
+{
+    currentModes[m] = savedModes[m];
+}
+
+bool Screen::getMode(int m) const
+{
+    return currentModes[m];
+}
+
+void Screen::saveCursor()
+{
+    savedState.cursorColumn = cuX;
+    savedState.cursorLine  = cuY;
+    savedState.rendition = currentRendition;
+    savedState.foreground = currentForeground;
+    savedState.background = currentBackground;
+}
+
+void Screen::restoreCursor()
+{
+    cuX     = qMin(savedState.cursorColumn,columns-1);
+    cuY     = qMin(savedState.cursorLine,lines-1);
+    currentRendition   = savedState.rendition; 
+    currentForeground   = savedState.foreground;
+    currentBackground   = savedState.background;
+    updateEffectiveRendition();
+}
+
+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
+        _bottomMargin = 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.
+    _topMargin=0;
+    _bottomMargin=lines-1;
+    initTabStops();
+    clearSelection();
+}
+
+void Screen::setDefaultMargins()
+{
+    _topMargin = 0;
+    _bottomMargin = 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
+
+   currentForeground, currentBackground 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::updateEffectiveRendition()
+{
+    effectiveRendition = currentRendition;
+    if (currentRendition & RE_REVERSE)
+    {
+        effectiveForeground = currentBackground;
+        effectiveBackground = currentForeground;
+    }
+    else
+    {
+        effectiveForeground = currentForeground;
+        effectiveBackground = currentBackground;
+    }
+
+    if (currentRendition & RE_BOLD)
+        effectiveForeground.toggleIntensive();
+}
+
+void Screen::copyFromHistory(Character* dest, int startLine, int count) const
+{
+    Q_ASSERT( startLine >= 0 && count > 0 && startLine + count <= history->getLines() );
+
+    for (int line = startLine; line < startLine + count; line++) 
+    {
+        const int length = qMin(columns,history->getLineLen(line));
+        const int destLineOffset  = (line-startLine)*columns;
+
+        history->getCells(line,0,length,dest + destLineOffset);
+
+        for (int column = length; column < columns; column++) 
+            dest[destLineOffset+column] = defaultChar;
+
+        // invert selected text
+        if (selBegin !=-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 (selBegin != -1 && isSelected(column,line + history->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 < history->getLines() + lines );
+
+    const int mergedLines = endLine - startLine + 1;
+
+    Q_ASSERT( size >= mergedLines * columns ); 
+    Q_UNUSED( size );
+
+    const int linesInHistoryBuffer = qBound(0,history->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 - history->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 < history->getLines() + lines );
+
+    const int mergedLines = endLine-startLine+1;
+    const int linesInHistory = qBound(0,history->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 (history->isWrappedLine(line))
+        {
+            result[index] = (LineProperty)(result[index] | LINE_WRAPPED);
+        }
+        index++;
+    }
+
+    // copy properties for lines in screen buffer
+    const int firstScreenLine = startLine + linesInHistory - history->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);
+
+    _topMargin=0;
+    _bottomMargin=lines-1;
+
+    setDefaultRendition();
+    saveCursor();
+
+    if ( clearScreen )
+        clear();
+}
+
+void Screen::clear()
+{
+    clearEntireScreen();
+    home();
+}
+
+void Screen::backspace()
+{
+    cuX = qMin(columns-1,cuX); // nowrap!
+    cuX = qMax(0,cuX-1);
+
+    if (screenLines[cuY].size() < cuX+1)
+        screenLines[cuY].resize(cuX+1);
+
+    if (BS_CLEARS) 
+        screenLines[cuY][cuX].character = ' ';
+}
+
+void Screen::tab(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::backtab(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()
+{
+    tabStops.resize(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);
+}
+
+void Screen::newLine()
+{
+    if (getMode(MODE_NewLine)) 
+        toStartOfLine();
+    index();
+}
+
+void Screen::checkSelection(int from, int to)
+{
+    if (selBegin == -1) 
+        return;
+    int scr_TL = loc(0, history->getLines());
+    //Clear entire selection if it overlaps region [from, to]
+    if ( (selBottomRight >= (from+scr_TL)) && (selTopLeft <= (to+scr_TL)) )
+        clearSelection();
+}
+
+void Screen::displayCharacter(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 < cuX+w)
+    {
+        screenLines[cuY].resize(cuX+w);
+    }
+
+    if (getMode(MODE_Insert)) insertChars(w);
+
+    lastPos = loc(cuX,cuY);
+
+    // check if selection is still valid.
+    checkSelection(lastPos, lastPos);
+
+    Character& currentChar = screenLines[cuY][cuX];
+
+    currentChar.character = c;
+    currentChar.foregroundColor = effectiveForeground;
+    currentChar.backgroundColor = effectiveBackground;
+    currentChar.rendition = effectiveRendition;
+
+    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 = effectiveForeground;
+        ch.backgroundColor = effectiveBackground;
+        ch.rendition = effectiveRendition;
+
+        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()
+{
+    _scrolledLines = 0;
+}
+
+void Screen::scrollUp(int n)
+{
+    if (n == 0) n = 1; // Default
+    if (_topMargin == 0) addHistLine(); // history.history
+    scrollUp(_topMargin, n);
+}
+
+QRect Screen::lastScrolledRegion() const
+{
+    return _lastScrolledRegion;
+}
+
+void Screen::scrollUp(int from, int n)
+{
+    if (n <= 0 || from + n > _bottomMargin) return;
+
+    _scrolledLines -= n;
+    _lastScrolledRegion = QRect(0,_topMargin,columns-1,(_bottomMargin-_topMargin));
+
+    //FIXME: make sure `topMargin', `bottomMargin', `from', `n' is in bounds.
+    moveImage(loc(0,from),loc(0,from+n),loc(columns-1,_bottomMargin));
+    clearImage(loc(0,_bottomMargin-n+1),loc(columns-1,_bottomMargin),' ');
+}
+
+void Screen::scrollDown(int n)
+{
+    if (n == 0) n = 1; // Default
+    scrollDown(_topMargin, n);
+}
+
+void Screen::scrollDown(int from, int n)
+{
+    _scrolledLines += n;
+
+    //FIXME: make sure `topMargin', `bottomMargin', `from', `n' is in bounds.
+    if (n <= 0) 
+        return;
+    if (from > _bottomMargin) 
+        return;
+    if (from + n > _bottomMargin) 
+        n = _bottomMargin - from;
+    moveImage(loc(0,from+n),loc(0,from),loc(columns-1,_bottomMargin-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) ? _topMargin : 0) ));
+}
+
+void Screen::home()
+{
+    cuX = 0;
+    cuY = 0;
+}
+
+void Screen::toStartOfLine()
+{
+    cuX = 0;
+}
+
+int Screen::getCursorX() const
+{
+    return cuX;
+}
+
+int Screen::getCursorY() const
+{
+    return cuY;
+}
+
+void Screen::clearImage(int loca, int loce, char c)
+{ 
+    int scr_TL=loc(0,history->getLines());
+    //FIXME: check positions
+
+    //Clear entire selection if it overlaps region to be moved...
+    if ( (selBottomRight > (loca+scr_TL) )&&(selTopLeft < (loce+scr_TL)) )
+    {
+        clearSelection();
+    }
+
+    int topLine = loca/columns;
+    int bottomLine = loce/columns;
+
+    Character clearCh(c,currentForeground,currentBackground,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;
+        }
+    }
+}
+
+void Screen::moveImage(int dest, int sourceBegin, int sourceEnd)
+{
+    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 (selBegin != -1)
+    {
+        bool beginIsTL = (selBegin == selTopLeft);
+        int diff = dest - sourceBegin; // Scroll by this amount
+        int scr_TL=loc(0,history->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 ((selTopLeft >= srca) && (selTopLeft <= srce))
+            selTopLeft += diff;
+        else if ((selTopLeft >= desta) && (selTopLeft <= deste))
+            selBottomRight = -1; // Clear selection (see below)
+
+        if ((selBottomRight >= srca) && (selBottomRight <= srce))
+            selBottomRight += diff;
+        else if ((selBottomRight >= desta) && (selBottomRight <= deste))
+            selBottomRight = -1; // Clear selection (see below)
+
+        if (selBottomRight < 0)
+        {
+            clearSelection();
+        }
+        else
+        {
+            if (selTopLeft < 0)
+                selTopLeft = 0;
+        }
+
+        if (beginIsTL)
+            selBegin = selTopLeft;
+        else
+            selBegin = selBottomRight;
+    }
+}
+
+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)
+{
+    currentRendition |= re;
+    updateEffectiveRendition();
+}
+
+void Screen::resetRendition(int re)
+{
+    currentRendition &= ~re;
+    updateEffectiveRendition();
+}
+
+void Screen::setDefaultRendition()
+{
+    setForeColor(COLOR_SPACE_DEFAULT,DEFAULT_FORE_COLOR);
+    setBackColor(COLOR_SPACE_DEFAULT,DEFAULT_BACK_COLOR);
+    currentRendition   = DEFAULT_RENDITION;
+    updateEffectiveRendition();
+}
+
+void Screen::setForeColor(int space, int color)
+{
+    currentForeground = CharacterColor(space, color);
+
+    if ( currentForeground.isValid() ) 
+        updateEffectiveRendition();
+    else 
+        setForeColor(COLOR_SPACE_DEFAULT,DEFAULT_FORE_COLOR);
+}
+
+void Screen::setBackColor(int space, int color)
+{
+    currentBackground = CharacterColor(space, color);
+
+    if ( currentBackground.isValid() ) 
+        updateEffectiveRendition();
+    else
+        setBackColor(COLOR_SPACE_DEFAULT,DEFAULT_BACK_COLOR);
+}
+
+void Screen::clearSelection() 
+{
+    selBottomRight = -1;
+    selTopLeft = -1;
+    selBegin = -1;
+}
+
+void Screen::getSelectionStart(int& column , int& line) const
+{
+    if ( selTopLeft != -1 )
+    {
+        column = selTopLeft % columns;
+        line = selTopLeft / columns; 
+    }
+    else
+    {
+        column = cuX + getHistLines();
+        line = cuY + getHistLines();
+    }
+}
+void Screen::getSelectionEnd(int& column , int& line) const
+{
+    if ( selBottomRight != -1 )
+    {
+        column = selBottomRight % columns;
+        line = selBottomRight / columns;
+    }
+    else
+    {
+        column = cuX + getHistLines();
+        line = cuY + getHistLines();
+    } 
+}
+void Screen::setSelectionStart(const int x, const int y, const bool mode)
+{
+    selBegin = loc(x,y); 
+    /* FIXME, HACK to correct for x too far to the right... */
+    if (x == columns) selBegin--;
+
+    selBottomRight = selBegin;
+    selTopLeft = selBegin;
+    blockSelectionMode = mode;
+}
+
+void Screen::setSelectionEnd( const int x, const int y)
+{
+    if (selBegin == -1) 
+        return;
+
+    int endPos =  loc(x,y); 
+
+    if (endPos < selBegin)
+    {
+        selTopLeft = endPos;
+        selBottomRight = selBegin;
+    }
+    else
+    {
+        /* FIXME, HACK to correct for x too far to the right... */
+        if (x == columns) 
+            endPos--;
+
+        selTopLeft = selBegin;
+        selBottomRight = endPos;
+    }
+
+    // Normalize the selection in column mode
+    if (blockSelectionMode)
+    {
+        int topRow = selTopLeft / columns;
+        int topColumn = selTopLeft % columns;
+        int bottomRow = selBottomRight / columns;
+        int bottomColumn = selBottomRight % columns;
+
+        selTopLeft = loc(qMin(topColumn,bottomColumn),topRow);
+        selBottomRight = loc(qMax(topColumn,bottomColumn),bottomRow);
+    }
+}
+
+bool Screen::isSelected( const int x,const int y) const
+{
+    bool columnInSelection = true;
+    if (blockSelectionMode)
+    {
+        columnInSelection = x >= (selTopLeft % columns) &&
+            x <= (selBottomRight % columns);
+    }
+
+    int pos = loc(x,y);
+    return pos >= selTopLeft && pos <= selBottomRight && columnInSelection;
+}
+
+QString Screen::selectedText(bool preserveLineBreaks) const
+{
+    QString result;
+    QTextStream stream(&result, QIODevice::ReadWrite);
+
+    PlainTextDecoder decoder;
+    decoder.begin(&stream);
+    writeSelectionToStream(&decoder , preserveLineBreaks);
+    decoder.end();
+
+    return result;
+}
+
+bool Screen::isSelectionValid() const
+{
+    return selTopLeft >= 0 && selBottomRight >= 0;
+}
+
+void Screen::writeSelectionToStream(TerminalCharacterDecoder* decoder , 
+        bool preserveLineBreaks) const
+{
+    if (!isSelectionValid())
+        return;
+    writeToStream(decoder,selTopLeft,selBottomRight,preserveLineBreaks);
+}
+
+void Screen::writeToStream(TerminalCharacterDecoder* decoder, 
+        int startIndex, int endIndex,
+        bool preserveLineBreaks) const
+{
+    int top = startIndex / columns;    
+    int left = startIndex % columns;
+
+    int bottom = endIndex / columns;
+    int right = endIndex % columns;
+
+    Q_ASSERT( top >= 0 && left >= 0 && bottom >= 0 && right >= 0 );
+
+    for (int y=top;y<=bottom;y++)
+    {
+        int start = 0;
+        if ( y == top || blockSelectionMode ) start = left;
+
+        int count = -1;
+        if ( y == bottom || blockSelectionMode ) count = right - start + 1;
+
+        const bool appendNewLine = ( y != bottom );
+        int copied = copyLineToStream( y,
+                start,
+                count,
+                decoder, 
+                appendNewLine,
+                preserveLineBreaks );
+
+        // if the selection goes beyond the end of the last line then
+        // append a new line character.
+        //
+        // this makes it possible to 'select' a trailing new line character after
+        // the text on a line.  
+        if ( y == bottom && 
+                copied < count    )
+        {
+            Character newLineChar('\n');
+            decoder->decodeLine(&newLineChar,1,0);
+        }
+    }    
+}
+
+int Screen::copyLineToStream(int line , 
+        int start, 
+        int count,
+        TerminalCharacterDecoder* decoder,
+        bool appendNewLine,
+        bool preserveLineBreaks) const
+{
+    //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 < history->getLines())
+    {
+        const int lineLength = history->getLineLen(line);
+
+        // ensure that start position is before end of line
+        start = qMin(start,qMax(0,lineLength-1));
+
+        // retrieve line from history buffer.  It is assumed
+        // that the history buffer does not store trailing white space
+        // at the end of the line, so it does not need to be trimmed here 
+        if (count == -1)
+        {
+            count = lineLength-start;
+        }
+        else
+        {
+            count = qMin(start+count,lineLength)-start;
+        }
+
+        // safety checks
+        assert( start >= 0 );
+        assert( count >= 0 );    
+        assert( (start+count) <= history->getLineLen(line) );
+
+        history->getCells(line,start,count,characterBuffer);
+
+        if ( history->isWrappedLine(line) )
+            currentLineProperties |= LINE_WRAPPED;
+    }
+    else
+    {
+        if ( count == -1 )
+            count = columns - start;
+
+        assert( count >= 0 );
+
+        const int screenLine = line-history->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]; 
+    }
+
+    // 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 );
+
+    return count;
+}
+
+void Screen::writeLinesToStream(TerminalCharacterDecoder* decoder, int fromLine, int toLine) const
+{
+    writeToStream(decoder,loc(0,fromLine),loc(columns-1,toLine));
+}
+
+void Screen::addHistLine()
+{
+    // add line to history buffer
+    // we have to take care about scrolling, too...
+
+    if (hasScroll())
+    {
+        int oldHistLines = history->getLines();
+
+        history->addCellsVector(screenLines[0]);
+        history->addLine( lineProperties[0] & LINE_WRAPPED );
+
+        int newHistLines = history->getLines();
+
+        bool beginIsTL = (selBegin == selTopLeft);
+
+        // 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 (selBegin != -1)
+            {
+                selTopLeft += columns;
+                selBottomRight += columns;
+            }
+        }
+
+        if (selBegin != -1)
+        {
+            // Scroll selection in history up
+            int top_BR = loc(0, 1+newHistLines);
+
+            if (selTopLeft < top_BR)
+                selTopLeft -= columns;
+
+            if (selBottomRight < top_BR)
+                selBottomRight -= columns;
+
+            if (selBottomRight < 0)
+                clearSelection();
+            else
+            {
+                if (selTopLeft < 0)
+                    selTopLeft = 0;
+            }
+
+            if (beginIsTL)
+                selBegin = selTopLeft;
+            else
+                selBegin = selBottomRight;
+        }
+    }
+
+}
+
+int Screen::getHistLines() const
+{
+    return history->getLines();
+}
+
+void Screen::setScroll(const HistoryType& t , bool copyPreviousScroll)
+{
+    clearSelection();
+
+    if ( copyPreviousScroll )
+        history = t.scroll(history);
+    else
+    {
+        HistoryScroll* oldScroll = history;
+        history = t.scroll(0);
+        delete oldScroll;
+    }
+}
+
+bool Screen::hasScroll() const
+{
+    return history->hasScroll();
+}
+
+const HistoryType& Screen::getScroll() const
+{
+    return history->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/src/Screen.h
@@ -0,0 +1,670 @@
+/*
+    This file is part of Konsole, KDE's terminal.
+
+    Copyright 2007-2008 by Robert Knight <robertknight@gmail.com>
+    Copyright 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
+
+    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
+
+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 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.  The cursor will stop at the 
+     * top margin.
+     */
+    void cursorUp(int n);
+    /** 
+     * Move the cursor down by @p n lines.  The cursor will stop at the
+     * bottom margin.
+     */
+    void cursorDown(int n);
+    /** 
+     * Move the cursor to the left by @p n columns.
+     * The cursor will stop at the first column.
+     */
+    void cursorLeft(int n);
+    /** 
+     * Move the cursor to the right by @p n columns.
+     * The cursor will stop at the right-most column.
+     */
+    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.  Equivalent to calling Return() followed by index()
+     */
+    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 toStartOfLine();
+    /** 
+     * 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 tab(int n = 1);
+    /** Moves the cursor @p n tab-stops to the left. */
+    void backtab(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 appearance (text color and style) of the cursor. 
+     * It can be restored by calling restoreCursor() 
+     */ 
+    void saveCursor();
+    /** Restores the position and appearance 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 appearance 
+     * of characters on the screen.
+     *
+     * @see Character::rendition
+     */  
+    void setRendition(int rendition);
+    /**
+     * Disables the given @p rendition flag.  Rendition flags control the appearance
+     * 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;
+   
+    /** Clear the entire screen and move the cursor to the home position.
+     * Equivalent to calling clearEntireScreen() followed by home().
+     */
+    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 displayCharacter(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.
+     *
+     * The top and bottom margins are reset to the top and bottom of the new 
+     * screen size.  Tab stops are also reset and the current selection is
+     * cleared.
+     */
+    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() const   
+    { return lines; }
+    /** Return the number of columns. */
+    int getColumns() const 
+    { return columns; }
+    /** Return the number of lines in the history buffer. */
+    int getHistLines() const;
+    /** 
+     * 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() const;
+    /** 
+     * Returns true if this screen keeps lines that are scrolled off the screen
+     * in a history buffer.
+     */
+    bool hasScroll() const;
+
+    /** 
+     * 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 blockSelectionMode True if the selection is in column mode.
+     */
+    void setSelectionStart(const int column, const int line, const bool blockSelectionMode);
+    
+    /**
+     * 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) const;
+    
+    /**
+     * Retrieves the end of the selection or the cursor position if there
+     * is no selection.
+     */
+    void getSelectionEnd(int& column , int& line) const;
+
+    /** Clears the current selection */
+    void clearSelection();
+
+    /** 
+      *  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) const;
+        
+    /**
+     * Copies part of the output to a stream.
+     *
+     * @param decoder A decoder which converts terminal characters into text
+     * @param fromLine The first line in the history to retrieve
+     * @param toLine The last line in the history to retrieve
+     */
+    void writeLinesToStream(TerminalCharacterDecoder* decoder, int fromLine, int toLine) const;
+
+    /**
+     * 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 converts 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) const;
+
+    /**
+     * Checks if the text between from and to is inside the current
+     * selection. If this is the case, the selection is cleared. The
+     * from and to are coordinates in the current viewable window.
+     * The loc(x,y) macro can be used to generate these values from a
+     * column,line pair.
+     *
+     * @param from The start of the area to check.
+     * @param to The end of the area to check
+     */
+    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.  Returns the number of lines actually copied,
+    //which may be less than 'count' if (start+count) is more than the number of characters on
+    //the line 
+    //
+    //line - the line number to copy, from 0 (the earliest line in the history) up to 
+    //         history->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 converts terminal characters (an Character array) into text
+    //appendNewLine - if true a new line character (\n) is appended to the end of the line
+    int  copyLineToStream(int line, 
+                          int start, 
+                          int count, 
+                          TerminalCharacterDecoder* decoder,
+                          bool appendNewLine,
+                          bool preserveLineBreaks) const;
+    
+    //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.
+    //
+    //NOTE: moveImage() can only move whole lines
+    void moveImage(int dest, int sourceBegin, int sourceEnd);
+    // scroll up 'i' lines in current region, clearing the bottom 'i' lines 
+    void scrollUp(int from, int i);
+    // scroll down 'i' lines in current region, clearing the top 'i' lines
+    void scrollDown(int from, int i);
+
+    void addHistLine();
+
+    void initTabStops();
+
+    void updateEffectiveRendition();
+    void reverseRendition(Character& p) const;
+
+    bool isSelectionValid() const;
+    // copies text from 'startIndex' to 'endIndex' to a stream
+    // startIndex and endIndex are positions generated using the loc(x,y) macro
+    void writeToStream(TerminalCharacterDecoder* decoder, int startIndex, 
+                       int endIndex, bool preserveLineBreaks = true) 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* history;
+    
+    // cursor location
+    int cuX;
+    int cuY;
+
+    // cursor color and rendition info
+    CharacterColor currentForeground;
+    CharacterColor currentBackground;
+    quint8 currentRendition; 
+
+    // margins ----------------
+    int _topMargin;
+    int _bottomMargin;
+
+    // states ----------------
+    int currentModes[MODES_SCREEN];
+    int savedModes[MODES_SCREEN];
+
+    // ----------------------------
+
+    QBitArray tabStops;
+
+    // selection -------------------
+    int selBegin; // The first location selected.
+    int selTopLeft;    // TopLeft Location.
+    int selBottomRight;    // Bottom Right Location.
+    bool blockSelectionMode;  // Column selection mode
+
+    // effective colors and rendition ------------
+    CharacterColor effectiveForeground; // These are derived from
+    CharacterColor effectiveBackground; // the cu_* variables above
+    quint8 effectiveRendition;          // to speed up operation
+
+    class SavedState  
+    {
+    public:
+        SavedState()
+        : cursorColumn(0),cursorLine(0),rendition(0) {}
+
+        int cursorColumn;
+        int cursorLine;
+        quint8 rendition;
+        CharacterColor foreground;
+        CharacterColor background;
+    };
+    SavedState savedState;
+        
+    // last position where we added a character
+    int lastPos;
+
+    static Character defaultChar;
+};
+
+#endif // SCREEN_H
new file mode 100644
--- /dev/null
+++ b/gui/src/ScreenWindow.cpp
@@ -0,0 +1,292 @@
+/*
+    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"
+
+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(); 
+}
new file mode 100644
--- /dev/null
+++ b/gui/src/ScreenWindow.h
@@ -0,0 +1,251 @@
+/*
+    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"
+
+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/src/Session.cpp
@@ -0,0 +1,1209 @@
+/*
+    This file is part of Konsole
+
+    Copyright 2006-2008 by Robert Knight <robertknight@gmail.com>
+    Copyright 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
+    Copyright 2009 by Thomas Dreibholz <dreibh@iem.uni-due.de>
+
+    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>
+#include <signal.h>
+
+// Qt
+#include <QtGui/QApplication>
+#include <QtCore/QByteRef>
+#include <QtCore/QDir>
+#include <QtCore/QFile>
+#include <QtCore/QRegExp>
+#include <QtCore/QStringList>
+#include <QtCore/QDate>
+
+#include "kprocess.h"
+#include "kptydevice.h"
+
+#include "ProcessInfo.h"
+#include "Pty.h"
+#include "TerminalDisplay.h"
+#include "ShellCommand.h"
+#include "Vt102Emulation.h"
+
+int Session::lastSessionId = 0;
+
+// HACK This is copied out of QUuid::createUuid with reseeding forced.
+// Required because color schemes repeatedly seed the RNG...
+// ...with a constant.
+QUuid createUuid()
+{
+    static const int intbits = sizeof(int)*8;
+    static int randbits = 0;
+    if (!randbits)
+    {
+        int max = RAND_MAX;
+        do { ++randbits; } while ((max=max>>1));
+    }
+
+    qsrand(uint(QDateTime::currentDateTime().toTime_t()));
+    qrand(); // Skip first
+
+    QUuid result;
+    uint *data = &(result.data1);
+    int chunks = 16 / sizeof(uint);
+    while (chunks--) {
+        uint randNumber = 0;
+        for (int filled = 0; filled < intbits; filled += randbits)
+            randNumber |= qrand()<<filled;
+         *(data+chunks) = randNumber;
+    }
+
+    result.data4[0] = (result.data4[0] & 0x3F) | 0x80;        // UV_DCE
+    result.data3 = (result.data3 & 0x0FFF) | 0x4000;        // UV_Random
+
+    return result;
+}
+
+Session::Session(QObject* parent) :
+   QObject(parent)
+   , _shellProcess(0)
+   , _emulation(0)
+   , _monitorActivity(false)
+   , _monitorSilence(false)
+   , _notifiedActivity(false)
+   , _autoClose(true)
+   , _wantedClose(false)
+   , _silenceSeconds(10)
+   , _addToUtmp(true)  
+   , _flowControl(true)
+   , _fullScripting(false)
+   , _sessionId(0)
+   , _sessionProcessInfo(0)
+   , _foregroundProcessInfo(0)
+   , _foregroundPid(0)
+   //, _zmodemBusy(false)
+   //, _zmodemProc(0)
+   //, _zmodemProgress(0)
+   , _hasDarkBackground(false)
+{
+    _uniqueIdentifier = createUuid();
+
+    //prepare DBus communication
+    //new SessionAdaptor(this);
+    _sessionId = ++lastSessionId;
+    
+    // JPS: commented out for lack of DBUS support by default on OSX
+    //QDBusConnection::sessionBus().registerObject(QLatin1String("/Sessions/")+QString::number(_sessionId), this);
+
+    //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&)) );
+    connect( _emulation, SIGNAL(flowControlKeyPressed(bool)) , this, 
+             SLOT(updateFlowControlState(bool)) );
+
+    //create new teletype for I/O with shell process
+    openTeletype(-1);
+
+    //setup timer for monitoring session activity
+    _monitorTimer = new QTimer(this);
+    _monitorTimer->setSingleShot(true);
+    connect(_monitorTimer, SIGNAL(timeout()), this, SLOT(monitorTimerDone()));
+}
+
+void Session::openTeletype(int fd)
+{
+    if (_shellProcess && isRunning())
+    {
+        //kWarning() << "Attempted to open teletype in a running session.";
+        return;
+    }
+
+    delete _shellProcess;
+
+    if (fd < 0)
+        _shellProcess = new Pty();
+    else
+        _shellProcess = new Pty(fd);
+
+    _shellProcess->setUtf8Mode(_emulation->utf8());
+
+    //connect teletype to emulation backend
+    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(finished(int,QProcess::ExitStatus)), this, SLOT(done(int)) );
+    connect( _emulation,SIGNAL(imageSizeChanged(int,int)),this,SLOT(updateWindowSize(int,int)) );
+}
+
+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->state() == QProcess::Running;
+}
+
+void Session::setCodec(QTextCodec* codec)
+{
+    emulation()->setCodec(codec);
+}
+
+bool Session::setCodec(QByteArray name)
+{
+    QTextCodec *codec = QTextCodec::codecForName(name);
+    if (codec) {
+        setCodec(codec);
+        return true;
+    }
+    return false;
+}
+
+QByteArray Session::codec()
+{
+    return _emulation->codec()->name();
+}
+
+void Session::setProgram(const QString& program)
+{
+    _program = ShellCommand::expand(program);
+}
+void Session::setInitialWorkingDirectory(const QString& dir)
+{
+  //_initialWorkingDir = KShell::tildeExpand(ShellCommand::expand(dir));
+  _initialWorkingDir = ShellCommand::expand(dir);
+}
+void Session::setArguments(const QStringList& arguments)
+{
+    _arguments = ShellCommand::expand(arguments);
+}
+
+QString Session::currentWorkingDirectory()
+{
+    // only returned cached value
+    if (_currentWorkingDir.isEmpty()) updateWorkingDirectory();
+    return _currentWorkingDir;
+}
+ProcessInfo* Session::updateWorkingDirectory()
+{
+    ProcessInfo *process = getProcessInfo();
+    _currentWorkingDir = process->validCurrentDir();
+    return process;
+}
+
+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*)) );
+}
+
+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();
+    }
+}
+
+QString Session::checkProgram(const QString& program) const
+{
+  // 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.isEmpty())
+      return QString();
+
+  // 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 = qgetenv("SHELL");
+  if ( exec.isEmpty() )
+        exec = "/bin/sh";
+  return program;
+}
+
+void Session::terminalWarning(const QString& message)
+{
+  static const QByteArray warningText = QByteArray("@info:shell Alert the user with red color text");
+    QByteArray messageText = message.toLocal8Bit();
+
+    static const char redPenOn[] = "\033[1m\033[31m";
+    static const char redPenOff[] = "\033[0m";
+
+    _emulation->receiveData(redPenOn,strlen(redPenOn));
+    _emulation->receiveData("\n\r\n\r",4);
+    _emulation->receiveData(warningText.constData(),strlen(warningText.constData()));
+    _emulation->receiveData(messageText.constData(),strlen(messageText.constData()));
+    _emulation->receiveData("\n\r\n\r",4);
+    _emulation->receiveData(redPenOff,strlen(redPenOff));
+}
+
+QString Session::shellSessionId() const
+{
+    QString friendlyUuid(_uniqueIdentifier.toString());
+    friendlyUuid.remove('-').remove('{').remove('}');
+
+    return friendlyUuid;
+}
+
+void Session::run()
+{
+  //check that everything is in place to run the session
+  if (_program.isEmpty())
+  {
+      //kWarning() << "Session::run() - program to run not set.";
+  }
+  if (_arguments.isEmpty())
+  {
+      //kWarning() << "Session::run() - no command line arguments specified.";
+  }
+  if (_uniqueIdentifier.isNull())
+  {
+      _uniqueIdentifier = createUuid();
+  }
+
+  const int CHOICE_COUNT = 3;
+  QString programs[CHOICE_COUNT] = {_program,qgetenv("SHELL"),"/bin/sh"};
+  QString exec;
+  int choice = 0;
+  while (choice < CHOICE_COUNT)
+  {
+    exec = checkProgram(programs[choice]);
+    if (exec.isEmpty())
+        choice++;
+    else
+        break;
+  }
+
+  // if a program was specified via setProgram(), but it couldn't be found, print a warning
+  if (choice != 0 && choice < CHOICE_COUNT && !_program.isEmpty())
+  {
+    QString msg;
+    QTextStream msgStream(&msg);
+    msgStream << "Could not find '" << _program << "', starting '" << exec << "' instead. Please check your profile settings.";
+    terminalWarning(msg);
+    //terminalWarning(i18n("Could not find '%1', starting '%2' instead.  Please check your profile settings.",_program.toLatin1().data(),exec.toLatin1().data())); 
+  }
+  // if none of the choices are available, print a warning
+  else if (choice == CHOICE_COUNT)
+  {
+      terminalWarning(QString("Could not find an interactive shell to start."));
+      return;
+  }
+  
+  // if no arguments are specified, fall back to program name
+  QStringList arguments = _arguments.join(QChar(' ')).isEmpty() ?
+                                                   QStringList() << exec : _arguments;
+
+  // JPS: commented out for lack of DBUS support by default on OSX
+  QString dbusService = ""; //QDBusConnection::sessionBus().baseService();
+  if (!_initialWorkingDir.isEmpty())
+    _shellProcess->setWorkingDirectory(_initialWorkingDir);
+  else
+    _shellProcess->setWorkingDirectory(QDir::homePath());
+
+  _shellProcess->setFlowControlEnabled(_flowControl);
+  _shellProcess->setErase(_emulation->eraseChar());
+
+  // 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";
+  _environment << backgroundColorHint;
+  _environment << QString("SHELL_SESSION_ID=%1").arg(shellSessionId());
+
+  int result = _shellProcess->start(exec,
+                                  arguments,
+                                  _environment,
+                                  windowId(),
+                                  _addToUtmp,
+                                  dbusService,
+                                  (QLatin1String("/Sessions/") +
+                                   QString::number(_sessionId)));
+
+  if (result < 0)
+  {
+    QString msg;
+    QTextStream msgStream(&msg);
+    msgStream << QString("Could not start program '") << exec << QString("' with arguments '") << arguments.join(" ") << QString("'.");
+    terminalWarning (msg);
+    //      terminalWarning(i18n("Could not start program '%1' with arguments '%2'.", exec.toLatin1().data(), arguments.join(" ").toLatin1().data()));
+    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;
+
+    if ((what == IconNameAndWindowTitle) || (what == WindowTitle)) 
+    {
+           if ( _userTitle != caption ) {
+            _userTitle = caption;
+            modified = true;
+        }
+    }
+
+    if ((what == IconNameAndWindowTitle) || (what == IconName))
+    {
+        if ( _iconText != caption ) {
+               _iconText = caption;
+            modified = true;
+        }
+    }
+
+    if (what == TextColor || what == BackgroundColor) 
+    {
+      QString colorString = caption.section(';',0,0);
+      QColor color = QColor(colorString);
+      if (color.isValid())
+      {
+          if (what == TextColor)
+                  emit changeForegroundColorRequest(color);
+          else
+                  emit changeBackgroundColorRequest(color);
+      }
+    }
+
+    if (what == SessionName) 
+    {
+        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 == ProfileChange) 
+    {
+        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", i18n("Silence in session '%1'", _nameTitle)propagateSize, QPixmap(),
+    //                QApplication::activeWindow(),
+    //                KNotification::CloseWhenWidgetActivated);
+    emit stateChanged(NOTIFYSILENCE);
+  }
+  else
+  {
+    emit stateChanged(NOTIFYNORMAL);
+  }
+
+  _notifiedActivity=false;
+}
+void Session::updateFlowControlState(bool suspended)
+{
+    if (suspended)
+    {
+        if (flowControlEnabled())
+        {
+            foreach(TerminalDisplay* display,_views)
+            {
+                if (display->flowControlWarningEnabled())
+                    display->outputSuspended(true);
+            }
+        }
+    } 
+    else
+    {
+        foreach(TerminalDisplay* display,_views)
+            display->outputSuspended(false);
+    }   
+}
+void Session::activityStateSet(int state)
+{
+  if (state==NOTIFYBELL)
+  {
+      emit bellRequest(QString("Bell in session '%1'").arg(_nameTitle.toLatin1().data()));
+  }
+  else if (state==NOTIFYACTIVITY)
+  {
+    if (_monitorSilence) {
+      _monitorTimer->start(_silenceSeconds*1000);
+    }
+
+    if ( _monitorActivity ) {
+      //FIXME:  See comments in Session::monitorTimerDone()
+      if (!_notifiedActivity) {
+        //KNotification::event("Activity", i18n("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::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() );
+            view->processFilters();
+        }
+    }
+
+    // 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 );
+    }
+}
+void Session::updateWindowSize(int lines, int columns)
+{
+    Q_ASSERT(lines > 0 && columns > 0);
+    _shellProcess->setWindowSize(lines,columns);
+}
+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::kill(int signal)
+{
+    int result = ::kill(_shellProcess->pid(),signal);    
+    
+    if ( result == 0 )
+    {
+        _shellProcess->waitForFinished();
+        return true;
+    }
+    else
+        return false;
+}
+
+void Session::close()
+{
+  _autoClose = true;
+  _wantedClose = true;
+
+  if (!isRunning() || !kill(SIGHUP))
+  {
+     if (isRunning())
+     {
+        //kWarning() << "Process" << _shellProcess->pid() << "did not respond to SIGHUP";
+
+        // close the pty and wait to see if the process finishes.  If it does,
+        // the done() slot will have been called so we can return.  Otherwise,
+        // emit the finished() signal regardless
+        _shellProcess->pty()->close();
+        if (_shellProcess->waitForFinished(3000))
+            return;
+
+        //kWarning() << "Unable to kill process" << _shellProcess->pid();
+     }
+
+     // Forced close.
+     QTimer::singleShot(1, this, SIGNAL(finished()));
+  }
+}
+
+void Session::sendText(const QString &text) const
+{
+  _emulation->sendText(text);
+}
+
+void Session::sendMouseEvent(int buttons, int column, int line, int eventType)
+{
+    _emulation->sendMouseEvent(buttons, column, line, eventType);
+}
+
+Session::~Session()
+{
+  if (_foregroundProcessInfo)
+      delete _foregroundProcessInfo;
+  if (_sessionProcessInfo)
+      delete _sessionProcessInfo;
+  delete _emulation;
+  delete _shellProcess;
+  //delete _zmodemProc;
+}
+
+void Session::done(int exitStatus)
+{
+  if (!_autoClose)
+  {
+    _userTitle = QString("@info:shell This session is done");
+    emit titleChanged();
+    return;
+  }
+
+  QString message;
+  QTextStream msgStream(&message);
+  if (!_wantedClose || exitStatus != 0)
+  {
+    if (_shellProcess->exitStatus() == QProcess::NormalExit)
+    {
+      msgStream << "Program '" << _program << "' exited with statis " << exitStatus << ".";
+      //message = i18n("Program '%1' exited with status %2.", _program.toLatin1().data(), exitStatus);
+
+    }
+    else
+    {
+      msgStream << "Program '" << _program << "' crashed.";
+      //message = i18n("Program '%1' crashed.", _program.toLatin1().data());
+	
+    }
+
+    //FIXME: See comments in Session::monitorTimerDone()
+    //KNotification::event("Finished", message , QPixmap(),
+    //                     QApplication::activeWindow(),
+    //                     KNotification::CloseWhenWidgetActivated);
+  }
+
+  if ( !_wantedClose && _shellProcess->exitStatus() != QProcess::NormalExit )
+      terminalWarning(message);
+  else
+        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();
+}
+
+ProcessInfo* Session::getProcessInfo()
+{
+    ProcessInfo* process;
+
+    if (isForegroundProcessActive())
+        process = _foregroundProcessInfo;
+    else
+    {
+        updateSessionProcessInfo();
+        process = _sessionProcessInfo;
+    }
+
+    return process;
+}
+
+void Session::updateSessionProcessInfo()
+{
+    Q_ASSERT(_shellProcess);
+    if (!_sessionProcessInfo)
+    {
+        _sessionProcessInfo = ProcessInfo::newInstance(processId());
+        _sessionProcessInfo->setUserHomeDir();
+    }
+    _sessionProcessInfo->update();
+}
+
+bool Session::updateForegroundProcessInfo()
+{
+    bool valid = (_foregroundProcessInfo != 0);
+
+    // has foreground process changed?
+    Q_ASSERT(_shellProcess);
+    int pid = _shellProcess->foregroundProcessGroup();
+    if (pid != _foregroundPid)
+    {
+        if (valid)
+            delete _foregroundProcessInfo;
+        _foregroundProcessInfo = ProcessInfo::newInstance(pid);
+        _foregroundPid = pid;
+        valid = true;
+    }
+
+    if (valid)
+    {
+        _foregroundProcessInfo->update();
+        valid = _foregroundProcessInfo->isValid();
+    }
+
+    return valid;
+}
+
+bool Session::isRemote()
+{
+    ProcessInfo* process = getProcessInfo();
+
+    bool ok = false;
+    return ( process->name(&ok) == "ssh" && ok );
+}
+
+QString Session::getDynamicTitle()
+{
+    // update current directory from process
+    ProcessInfo* process = updateWorkingDirectory();
+
+    // format tab titles using process info
+    bool ok = false;
+    QString title;
+    if ( process->name(&ok) == "ssh" && ok )
+    {
+        SSHProcessInfo sshInfo(*process);
+        title = sshInfo.format(tabTitleFormat(Session::RemoteTabTitle));
+    }
+    else
+        title = process->format(tabTitleFormat(Session::LocalTabTitle));
+
+    return title;
+}
+
+void Session::setIconName(const QString& iconName)
+{
+    if ( iconName != _iconName )
+    {
+        _iconName = iconName;
+        emit titleChanged();
+    }
+}
+
+void Session::setIconText(const QString& iconText)
+{
+  _iconText = 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)
+{
+  _flowControl = enabled;
+
+  if (_shellProcess)  
+    _shellProcess->setFlowControlEnabled(_flowControl);
+  emit flowControlEnabledChanged(enabled);
+}
+bool Session::flowControlEnabled() const
+{
+    if (_shellProcess)
+            return _shellProcess->flowControlEnabled();
+    else
+            return _flowControl;
+}
+
+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::processId() const
+{
+    return _shellProcess->pid();
+}
+
+void Session::setTitle(int role , const QString& title)
+{
+    switch (role) {
+    case (0):
+        this->setTitle(Session::NameRole, title);
+        break;
+    case (1):
+        this->setTitle(Session::DisplayedTitleRole, title);
+        break;
+    }
+}
+
+QString Session::title(int role) const
+{
+    switch (role) {
+    case (0):
+        return this->title(Session::NameRole);
+    case (1):
+        return this->title(Session::DisplayedTitleRole);
+    default:
+        return QString();
+    }
+}
+
+void Session::setTabTitleFormat(int context , const QString& format)
+{
+    switch (context) {
+    case (0):
+        this->setTabTitleFormat(Session::LocalTabTitle, format);
+        break;
+    case (1):
+        this->setTabTitleFormat(Session::RemoteTabTitle, format);
+        break;
+    }
+}
+
+QString Session::tabTitleFormat(int context) const
+{
+    switch (context) {
+    case (0):
+        return this->tabTitleFormat(Session::LocalTabTitle);
+    case (1):
+        return this->tabTitleFormat(Session::RemoteTabTitle);
+    default:
+        return QString();
+    }
+}
+
+int Session::foregroundProcessId()
+{
+    int pid;
+
+    bool ok = false;
+    pid = getProcessInfo()->pid(&ok);
+    if (!ok)
+        pid = -1;
+
+    return pid;
+}
+
+bool Session::isForegroundProcessActive()
+{
+    // foreground process info is always updated after this
+    return updateForegroundProcessInfo() && (processId() != _foregroundPid);
+}
+
+QString Session::foregroundProcessName()
+{
+    QString name;
+
+    if (updateForegroundProcessInfo()) 
+    {
+        bool ok = false;
+        name = _foregroundProcessInfo->name(&ok);
+        if (!ok)
+            name.clear();
+    }
+
+    return name;
+}
+
+SessionGroup::SessionGroup(QObject* parent)
+    : QObject(parent), _masterMode(0)
+{
+}
+SessionGroup::~SessionGroup()
+{
+}
+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)
+{
+    connect(session,SIGNAL(finished()),this,SLOT(sessionFinished()));
+    _sessions.insert(session,false);
+}
+void SessionGroup::removeSession(Session* session)
+{
+    disconnect(session,SIGNAL(finished()),this,SLOT(sessionFinished()));
+    setMasterStatus(session,false);
+    _sessions.remove(session);
+}
+void SessionGroup::sessionFinished()
+{
+    Session* session = qobject_cast<Session*>(sender());
+    Q_ASSERT(session);
+    removeSession(session);
+}
+void SessionGroup::setMasterMode(int mode)
+{
+   _masterMode = mode;
+}
+QList<Session*> SessionGroup::masters() const
+{
+    return _sessions.keys(true);
+}
+void SessionGroup::setMasterStatus(Session* session , bool master)
+{
+    const bool wasMaster = _sessions[session];
+
+    if (wasMaster == master) {
+        // No status change -> nothing to do.
+        return;
+    }
+    _sessions[session] = master;
+
+    if(master) {
+        connect( session->emulation() , SIGNAL(sendData(const char*,int)) , this,
+                 SLOT(forwardData(const char*,int)) );
+    }
+    else {
+        disconnect( session->emulation() , SIGNAL(sendData(const char*,int)) , this,
+                    SLOT(forwardData(const char*,int)) );
+    }
+}
+void SessionGroup::forwardData(const char* data, int size)
+{
+    static bool _inForwardData = false;
+    if(_inForwardData) {   // Avoid recursive calls among session groups!
+       // A recursive call happens when a master in group A calls forwardData()
+       // in group B. If one of the destination sessions in group B is also a
+       // master of a group including the master session of group A, this would
+       // again call forwardData() in group A, and so on.
+       return;
+    }
+    
+    _inForwardData = true;
+    QListIterator<Session*> iter(_sessions.keys());
+    while(iter.hasNext()) {
+        Session* other = iter.next();
+        if(!_sessions[other]) {
+           other->emulation()->sendString(data, size);
+        }
+    }
+    _inForwardData = false;
+}
+
+
new file mode 100644
--- /dev/null
+++ b/gui/src/Session.h
@@ -0,0 +1,752 @@
+/*
+    This file is part of Konsole, an X terminal.
+
+    Copyright 2007-2008 by Robert Knight <robertknight@gmail.com>
+    Copyright 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
+    Copyright 2009 by Thomas Dreibholz <dreibh@iem.uni-due.de>
+
+    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/QByteRef>
+#include <QtCore/QSize>
+#include <QUuid>
+#include <QWidget>
+
+// Konsole
+#include "History.h"
+
+class KProcess;
+class KUrl;
+class Emulation;
+class Pty;
+class ProcessInfo;
+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
+Q_CLASSINFO("D-Bus Interface", "org.kde.konsole.Session")
+
+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.
+   */
+  explicit Session(QObject* parent = 0);
+  ~Session();
+
+  /** 
+   * Connect to an existing terminal.  When a new Session() is constructed it 
+   * automatically searches for and opens a new teletype.  If you want to 
+   * use an existing teletype (given its file descriptor) call this after
+   * constructing the session.
+   *
+   * Calling openTeletype() while a session is running has no effect.
+   *
+   * @param masterFd The file descriptor of the pseudo-teletype master (See KPtyProcess::KPtyProcess())
+   */
+  void openTeletype(int masterFd);
+
+  /**
+   * Returns true if the session is currently running.  This will be true
+   * after run() has been called successfully.
+   */
+  bool isRunning() 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 unique ID for this session. */
+  int sessionId() 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
+  };
+
+  /**
+   * Returns true if the session currently contains a connection to a 
+   * remote computer.  It currently supports ssh.
+   */
+  bool isRemote();
+
+  /**
+   * 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 );
+
+  /**
+   * Returns the current directory of the foreground process in the session
+   */
+  QString currentWorkingDirectory();
+
+  /**
+   * 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();
+
+  /**
+   * 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
+  };
+
+  /**
+   * 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;
+
+  /** Convenience method used to read the name property.  Returns title(Session::NameRole). */
+  QString nameTitle() const { return title(Session::NameRole); }
+  /** Returns a title generated from tab format and process information. */
+  QString getDynamicTitle();
+
+  /** 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;
+
+  /** Return URL for the session. */
+  //KUrl getUrl();
+
+  /** 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;
+
+  /** 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;
+
+  /** 
+   * Specifies whether a utmp entry should be created for the pty used by this session.
+   * If true, KPty::login() is called when the session is started.
+   */
+  void setAddToUtmp(bool);
+
+  /**
+   * Specifies whether to close the session automatically when the terminal
+   * process terminates.
+   */
+  void setAutoClose(bool b) { _autoClose = b; }
+
+  /** Returns true if the user has started a program in the session. */
+  bool isForegroundProcessActive();
+
+  /** Returns the name of the current foreground process. */
+  QString foregroundProcessName();
+
+  /** 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 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; }
+
+ /** 
+   * Possible values of the @p what parameter for setUserTitle()
+   * See "Operating System Controls" section on http://rtfm.etla.org/xterm/ctlseq.html 
+   */
+  enum UserTitleChange
+  {
+      IconNameAndWindowTitle     = 0,
+    IconName                 = 1,
+    WindowTitle                = 2,
+    TextColor                = 10,
+    BackgroundColor            = 11,
+    SessionName                = 30,
+    ProfileChange            = 50     // this clashes with Xterm's font change command
+  };
+
+  // Sets the text codec used by this sessions terminal emulation.
+  void setCodec(QTextCodec* codec);
+
+  // session management
+  //void saveSession(KConfigGroup& group);
+  //void restoreSession(KConfigGroup& group);
+
+public slots:
+
+  /**
+   * Starts the terminal session.
+   *
+   * This creates the terminal process and connects the teletype to it.
+   */
+  void run();
+
+  /**
+   * Returns the environment of this session as a list of strings like
+   * VARIABLE=VALUE
+   */
+  Q_SCRIPTABLE QStringList environment() const;
+
+  /**
+   * Sets the environment for this session.
+   * @p environment should be a list of strings like
+   * VARIABLE=VALUE
+   */
+  Q_SCRIPTABLE void setEnvironment(const QStringList& environment);
+
+  /**
+   * Closes the terminal session.  This sends a hangup signal
+   * (SIGHUP) to the terminal process and causes the finished()  
+   * signal to be emitted.  If the process does not respond to the SIGHUP signal
+   * then the terminal connection (the pty) is closed and Konsole waits for the 
+   * process to exit.
+   */
+  Q_SCRIPTABLE 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.
+   *
+   * @param what The feature being changed.  Value is one of UserTitleChange
+   * @param caption The text part of the terminal command
+   */
+  void setUserTitle( int what , const QString &caption );
+
+  /**
+   * 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.
+   */
+  Q_SCRIPTABLE void setMonitorActivity(bool);
+
+  /** Returns true if monitoring for activity is enabled. */
+  Q_SCRIPTABLE 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()
+   */
+  Q_SCRIPTABLE void setMonitorSilence(bool);
+
+  /**
+   * Returns true if monitoring for inactivity (silence)
+   * in the session is enabled.
+   */
+  Q_SCRIPTABLE bool isMonitorSilence() const;
+
+  /** See setMonitorSilence() */
+  Q_SCRIPTABLE void setMonitorSilenceSeconds(int seconds);
+
+  /**
+   * Sets whether flow control is enabled for this terminal
+   * session.
+   */
+  Q_SCRIPTABLE void setFlowControlEnabled(bool enabled);
+
+  /** Returns whether flow control is enabled for this terminal session. */
+  Q_SCRIPTABLE bool flowControlEnabled() const;
+
+  /**
+   * Sends @p text to the current foreground terminal program.
+   */
+  Q_SCRIPTABLE void sendText(const QString& text) const;
+
+   /**
+    * Sends a mouse event of type @p eventType emitted by button
+    * @p buttons on @p column/@p line to the current foreground
+    * terminal program
+    */
+   Q_SCRIPTABLE void sendMouseEvent(int buttons, int column, int line, int eventType);
+
+   /**
+   * Returns the process id of the terminal process.
+   * This is the id used by the system API to refer to the process.
+   */
+  Q_SCRIPTABLE 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.
+   */
+  Q_SCRIPTABLE int foregroundProcessId();
+
+  /** Sets the text codec used by this sessions terminal emulation.
+    * Overloaded to accept a QByteArray for convenience since DBus
+    * does not accept QTextCodec directky.
+    */
+  Q_SCRIPTABLE bool setCodec(QByteArray codec);
+
+  /** Returns the codec used to decode incoming characters in this
+   * terminal emulation
+   */
+  Q_SCRIPTABLE QByteArray codec();
+
+  /** Sets the session's title for the specified @p role to @p title.
+   *  This is an overloaded member function for setTitle(TitleRole, QString)
+   *  provided for convenience since enum data types may not be
+   *  exported directly through DBus
+   */
+  Q_SCRIPTABLE void setTitle(int role, const QString& title);
+
+  /** Returns the session's title for the specified @p role.
+   * This is an overloaded member function for  setTitle(TitleRole)
+   * provided for convenience since enum data types may not be
+   * exported directly through DBus
+   */
+  Q_SCRIPTABLE QString title(int role) const;
+
+  /** Returns the "friendly" version of the QUuid of this session.
+  * This is a QUuid with the braces and dashes removed, so it cannot be
+  * used to construct a new QUuid. The same text appears in the
+  * SHELL_SESSION_ID environment variable.
+  */
+  Q_SCRIPTABLE QString shellSessionId() const;
+
+  /** Sets the session's tab title format for the specified @p context to @p format.
+   *  This is an overloaded member function for setTabTitleFormat(TabTitleContext, QString)
+   *  provided for convenience since enum data types may not be
+   *  exported directly through DBus
+   */
+  Q_SCRIPTABLE void setTabTitleFormat(int context, const QString& format);
+
+  /** Returns the session's tab title format for the specified @p context.
+   * This is an overloaded member function for tabTitleFormat(TitleRole)
+   * provided for convenience since enum data types may not be
+   * exported directly through DBus
+   */
+  Q_SCRIPTABLE QString tabTitleFormat(int context) const;
+
+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 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&);
+  /** 
+   * Requests that the text color of views on this session should
+   * be changed to @p color.
+   */
+  void changeForegroundColorRequest(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 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();
+
+  void updateFlowControlState(bool suspended);
+  void updateWindowSize(int lines, int columns);
+private:
+
+  void updateTerminalSize();
+  WId windowId() const;
+  bool kill(int signal);
+  // print a warning message in the terminal.  This is used
+  // if the program fails to start, or if the shell exits in 
+  // an unsuccessful manner
+  void terminalWarning(const QString& message);
+  // checks that the binary 'program' is available and can be executed
+  // returns the binary name if available or an empty string otherwise
+  QString checkProgram(const QString& program) const;
+  ProcessInfo* getProcessInfo();
+  void updateSessionProcessInfo();
+  bool updateForegroundProcessInfo();
+  ProcessInfo* updateWorkingDirectory();
+
+  QUuid            _uniqueIdentifier; // SHELL_SESSION_ID
+
+  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;
+  QString        _currentWorkingDir;
+
+  ProcessInfo*   _sessionProcessInfo;
+  ProcessInfo*   _foregroundProcessInfo;
+  int            _foregroundPid;
+
+  // 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(QObject* parent);
+    /** 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 slots:
+    void sessionFinished();
+    void forwardData(const char* data, int size);
+
+private:
+    QList<Session*> masters() const;
+
+    // maps sessions to their master status
+    QHash<Session*,bool> _sessions;
+
+    int _masterMode;
+};
+
+#endif
+
+/*
+  Local Variables:
+  mode: c++
+  c-file-style: "stroustrup"
+  indent-tabs-mode: nil
+  tab-width: 4
+  End:
+*/
new file mode 100644
--- /dev/null
+++ b/gui/src/ShellCommand.cpp
@@ -0,0 +1,165 @@
+/*
+    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>
+
+// 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/src/ShellCommand.h
@@ -0,0 +1,88 @@
+/*
+    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>
+
+/** 
+ * 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/src/SimpleEditor.cpp
@@ -0,0 +1,288 @@
+/* Copyright (C) 2010 P.L. Lucas
+ *
+ * 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.
+ */
+
+#include "SimpleEditor.h"
+#include <QFile>
+#include <QTextStream>
+#include <QTextBlock>
+#include <QFileInfo>
+#include <QDir>
+
+SimpleEditor::SimpleEditor(QWidget *parent)
+    : QPlainTextEdit(parent),
+      m_syntaxHighlighter(0),
+      m_firstTimeUse(true) {
+
+    m_completerModel = new QStringListModel ();
+    m_completer = new QCompleter(m_completerModel, this);
+    m_completer->setCompletionMode(QCompleter::PopupCompletion);
+    m_completer->setWidget(this);
+    m_autoIndentation = true;
+    m_automaticIndentationStatement = true;
+
+    QFont font;
+    font.setFamily("Courier");
+    font.setPointSize(10);
+    setFont(font);
+
+    connect(m_completer, SIGNAL(activated(const QString &)), this, SLOT(activated(const QString &)));
+    connect(this, SIGNAL(cursorPositionChanged()), this, SLOT(cursorPositionChangedCallBack()));
+    connect(document(), SIGNAL(contentsChange(int, int, int)), this, SLOT(autoComplete(int, int, int)));
+}
+
+void SimpleEditor::loadSyntaxXMLDescription() {
+    QString installPath = QString("../syntax_files")
+        + QDir::separator();
+
+    QFileInfo file(m_currentFileName);
+    QString suffix = file.suffix();
+
+    if(m_commandsCompletionList.isEmpty()) {
+        QString home = QDir::home().path()
+            + QDir::separator()
+            + ".qtoctave"
+            + QDir::separator()
+            + "commands.txt";
+
+        QFile file(home);
+
+        if(file.open(QFile::ReadOnly)) {
+            char buf[1024];
+            while(file.readLine(buf, sizeof(buf)) >= 0) {
+                m_commandsCompletionList.append(QString(buf).trimmed());
+            }
+            file.close();
+        }
+    }
+
+    QFileInfo xml(installPath + suffix + ".xml");
+    if(xml.exists()) {
+        m_syntaxHighlighter = new SyntaxHighlighter(document());
+        m_syntaxHighlighter->load(xml.absoluteFilePath());
+        m_syntaxHighlighter->setDocument(document());
+    }
+}
+
+bool SimpleEditor::load(QString file) {
+    if(file.isEmpty()) {
+        setPlainText("");
+        m_currentFileName = file;
+        return true;
+    }
+
+    FILE *input = fopen(file.toLocal8Bit().data(),"r");
+    if(!input)
+        return false;
+    fclose(input);
+    QFile in(file);
+    if(!in.open(QIODevice::ReadOnly | QIODevice::Text)) {
+        return false;
+    }
+    QByteArray data = in.readAll();
+    setPlainText(QString::fromLocal8Bit(data));
+    m_currentFileName = file;
+    m_firstTimeUse = false;
+
+    loadSyntaxXMLDescription();
+
+    return true;
+}
+
+bool SimpleEditor::save() {
+    QFile::remove(m_currentFileName + "~");
+    QFile::copy(m_currentFileName, m_currentFileName + "~");
+    FILE *out=fopen(m_currentFileName.toLocal8Bit().data(),"w");
+    if(!out)
+        return false;
+    fprintf(out, "%s", toPlainText().toLocal8Bit().data());
+    fclose(out);
+    document()->setModified(false);
+    return true;
+}
+
+void SimpleEditor::keyPressEvent(QKeyEvent * keyEvent) {
+    //In all cases completer popup must been hided.
+    if(keyEvent->key() != Qt::Key_Return && keyEvent->key() != Qt::Key_Enter) {
+        QAbstractItemView *view = m_completer->popup();
+        if(view->isVisible()) view->hide();
+    }
+
+    if(keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter) {
+        QAbstractItemView *view = m_completer->popup();
+        if(view->isVisible()) {
+            QString word = view->currentIndex().data().toString();
+            if(word.isEmpty()) {
+                word = m_completer->currentCompletion();
+            }
+            activated(word);
+            return;
+        } else if(m_autoIndentation) {
+            QTextCursor cursor = textCursor();
+            QString line = cursor.block().text();
+            QString line2 = line;
+            for(int i=0;i<line.length();i++) {
+                if(line[i] != ' ' && line[i] != '\t') {
+                    line.resize(i);
+                    break;
+                }
+            }
+
+            cursor.insertText("\n" + line);
+            if(m_automaticIndentationStatement) {
+                    QRegExp re("^while .*|^if .*|^for .*|^switch .*|^do$|^try|^function .*|^else$|^elseif .*");
+                    if(re.exactMatch(line2.trimmed())) {
+                            cursor.insertText("\t");
+                    }
+            }
+            setTextCursor(cursor);
+        } else {
+            QPlainTextEdit::keyPressEvent(keyEvent);
+        }
+    } else if(keyEvent->key() == Qt::Key_Tab) {
+            QTextCursor cursor=textCursor();
+            int start=cursor.selectionStart();
+            int end=cursor.selectionEnd();
+            if(start == end) {
+                QPlainTextEdit::keyPressEvent(keyEvent);
+                return;
+            }
+            cursor.beginEditBlock();
+            cursor.setPosition(end);
+            end=cursor.blockNumber();
+            cursor.setPosition(start);
+            cursor.movePosition(QTextCursor::StartOfBlock);
+            while(true) {
+                cursor.insertText("\t");
+                if(cursor.blockNumber()>=end) {
+                    break;
+                }
+                cursor.movePosition(QTextCursor::NextBlock);
+            }
+            cursor.endEditBlock();
+    } else if(keyEvent->key()==Qt::Key_Backtab) {
+        QTextCursor cursor=textCursor();
+        int start=cursor.selectionStart();
+        int end=cursor.selectionEnd();
+        if(start==end) {
+            QPlainTextEdit::keyPressEvent(keyEvent);
+            return;
+        }
+        cursor.beginEditBlock();
+        cursor.setPosition(end);
+        end=cursor.blockNumber();
+        cursor.setPosition(start);
+        cursor.movePosition(QTextCursor::StartOfBlock);
+        while(true) {
+            QString line=cursor.block().text();
+            if(line.length()>0 && (line[0]==' ' || line[0] =='\t')) {
+                cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor);
+                cursor.removeSelectedText();
+            }
+            if(cursor.blockNumber()>=end) break;
+            cursor.movePosition(QTextCursor::NextBlock);
+            cursor.movePosition(QTextCursor::StartOfBlock);
+        }
+        cursor.endEditBlock();
+    } else {
+        if(keyEvent->key()==(Qt::Key_B) && Qt::ControlModifier==keyEvent->modifiers()) {
+            autoComplete(0);
+            return;
+        }
+        QPlainTextEdit::keyPressEvent(keyEvent);
+    }
+}
+
+void SimpleEditor::setCharFormat(QTextCharFormat charFormat) {
+    this->m_charFormat=charFormat;
+    QTextCursor cursor=textCursor();
+    cursor.movePosition(QTextCursor::Start);
+    cursor.setCharFormat(charFormat);
+    cursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor);
+    setFont(charFormat.font());
+
+    QFontMetrics fm(charFormat.font());
+    int textWidthInPixels = fm.width("        ");
+    setTabStopWidth(textWidthInPixels);
+}
+
+void SimpleEditor::activated(const QString& text) {
+    QAbstractItemView *view=m_completer->popup();
+    QTextCursor cursor=textCursor();
+    cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::KeepAnchor);
+    cursor.insertText(text);
+    view->hide();
+}
+
+void SimpleEditor::autoComplete(int position, int charsRemoved, int charsAdded) {
+    if(charsAdded==1)
+            autoComplete();
+}
+
+void SimpleEditor::autoComplete(int size) {
+    QTextCursor cursor = textCursor();
+    cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::KeepAnchor);
+    if(cursor.selectedText().endsWith(" ")
+            || cursor.selectedText().trimmed().length() < size) {
+        return;
+    }
+
+    QStringList list=toPlainText().split(QRegExp("\\W+"));
+    list.removeDuplicates();
+    list.removeOne(cursor.selectedText());
+    list.sort();
+    list.append(m_commandsCompletionList);
+
+    m_completerModel->setStringList(list);
+    m_completer->setCompletionPrefix(cursor.selectedText());
+
+    if(m_completer->completionCount() > 0) {
+            QRect r=cursorRect(cursor);
+            r.setWidth(200);
+            m_completer->complete(r);
+    }
+}
+
+QString SimpleEditor::getFileName() {
+    return m_currentFileName;
+}
+
+void SimpleEditor::setFile(QString file) {
+    m_currentFileName = file;
+    loadSyntaxXMLDescription();
+}
+
+void SimpleEditor::cursorPositionChangedCallBack() {
+    if(m_syntaxHighlighter)
+            m_syntaxHighlighter->setFormatPairBrackets(this);
+}
+
+void SimpleEditor::publicBlockBoundingRectList(QVector<qreal> &list, int &firstLine) {
+    qreal pageBottom = height();
+    QPointF offset = contentOffset();
+    QTextBlock block = firstVisibleBlock();
+    firstLine = block.blockNumber() + 1;
+    qreal first_position = blockBoundingGeometry(block).topLeft().y();
+    for(; block.isValid(); block = block.next()) {
+        QRectF position = blockBoundingGeometry(block);
+        qreal y = position.topLeft().y() + offset.y() - first_position;
+        if(y > pageBottom)
+            break;
+        list.append(y);
+    }
+}
+
new file mode 100644
--- /dev/null
+++ b/gui/src/SimpleEditor.h
@@ -0,0 +1,61 @@
+/* Copyright (C) 2010 P.L. Lucas
+ *
+ * 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.
+ */
+
+#ifndef SIMPLEEDITOR_H
+#define SIMPLEEDITOR_H
+
+#include <QPlainTextEdit>
+#include <QCompleter>
+#include <QStringListModel>
+#include "SyntaxHighlighter.h"
+
+class SimpleEditor : public QPlainTextEdit {
+    Q_OBJECT
+public:
+    SimpleEditor(QWidget * parent = 0);
+    bool load(QString file);
+    bool save();
+    QString getFileName();
+    void setFile(QString file);
+    void setCharFormat(QTextCharFormat m_charFormat);
+    void publicBlockBoundingRectList(QVector<qreal>  &list, int &firstLine);
+    void loadSyntaxXMLDescription();
+
+public slots:
+    void activated(const QString& text);
+    void cursorPositionChangedCallBack();
+    void autoComplete(int size = 3);
+    void autoComplete(int position, int charsRemoved, int charsAdded);
+
+protected:
+    virtual void keyPressEvent(QKeyEvent * e);
+
+private:
+    bool m_firstTimeUse;
+    QString m_currentFileName;
+    QTextCharFormat m_charFormat;
+    QCompleter *m_completer;
+    QStringListModel *m_completerModel;
+    SyntaxHighlighter *m_syntaxHighlighter;
+    QStringList m_commandsCompletionList;
+    bool m_autoIndentation;
+    bool m_automaticIndentationStatement;
+};
+
+#endif // SIMPLEEDITOR_H
+
new file mode 100644
--- /dev/null
+++ b/gui/src/SyntaxHighlighter.cpp
@@ -0,0 +1,486 @@
+/* Copyright (C) 2010 P.L. Lucas
+ *
+ * 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.
+ */
+
+
+#include "SyntaxHighlighter.h"
+#include <QXmlStreamReader>
+#include <QStack>
+#include <QFile>
+#include <stdio.h>
+
+SyntaxHighlighter::SyntaxHighlighter(QObject * parent):QSyntaxHighlighter(parent)
+{
+}
+
+
+bool SyntaxHighlighter::load(QString file)
+{
+	QXmlStreamReader xml;
+	QStack <QString> stack;
+	QFile fileDevice(file);
+	if (!fileDevice.open(QFile::ReadOnly | QFile::Text)) {
+	         return false;
+	}
+	
+	xml.setDevice(&fileDevice);
+	
+	QMap <QString,QString> values;
+	
+	QVector<QString> xmlMainItems;
+	xmlMainItems << "item" << "block" << "bracket";
+	
+	int ruleOrder=0;
+	
+	while (!xml.atEnd())
+	{
+		QXmlStreamReader::TokenType tokenType=xml.readNext();
+		switch(tokenType)
+		{
+			case QXmlStreamReader::StartElement:
+				if(xml.name()!="syntax")
+				{
+					if( xmlMainItems.contains(xml.name().toString()) )
+						stack.push(xml.name().toString());
+					else
+						values[xml.name().toString()]=xml.readElementText().trimmed();
+				}
+			break;
+			case QXmlStreamReader::EndElement:
+				if(stack.isEmpty()) break;
+				QString name=stack.top();
+				if(name==xml.name()) stack.pop();
+				if(stack.isEmpty())
+				{
+					QTextCharFormat format;
+					if(values.contains("bold") && values["bold"]=="true") format.setFontWeight(QFont::Bold);
+					if(values.contains("underline") && values["underline"]=="true") format.setFontUnderline(true);
+					if(values.contains("italic") && values["italic"]=="true") format.setFontItalic(true);
+					if(values.contains("foreground")) format.setForeground(QBrush(QColor(values["foreground"])));
+					if(values.contains("background")) format.setBackground(QBrush(QColor(values["background"])));
+					if(name=="item")
+					{
+						HighlightingRule rule;
+						rule.format=format;
+						rule.pattern=QRegExp(values["pattern"]);
+						rule.ruleOrder=ruleOrder++;
+						highlightingRules.append(rule);
+						values.clear();
+					}
+					else if(name=="block" || name=="bracket")
+					{
+						HighlightingBlockRule rule;
+						rule.format=format;
+						rule.startPattern=QRegExp(values["startPattern"]);
+						rule.endPattern=QRegExp(values["endPattern"]);
+						rule.ruleOrder=ruleOrder++;
+						if(name=="block") highlightingBlockRules.append(rule);
+						else highlightingBracketsRules.append(rule); //Bracket rule
+						values.clear();
+					}
+				}
+			break;
+		}
+	}
+	if (xml.hasError())
+	{
+		// do error handling
+		printf("Error %s: %ld:%ld %s\n", file.toLocal8Bit().data(), xml.lineNumber(), xml.columnNumber(), xml.errorString().toLocal8Bit().data() );
+		return false;
+	}
+	
+	return true;
+}
+
+SyntaxHighlighter::Rule1st SyntaxHighlighter::highlight1stRule(const QString & text, int startIndex)
+{
+	Rule1st rule1st;
+	rule1st.startIndex=text.length();
+	rule1st.rule=-1;
+	
+	for(int i=0; i<highlightingRules.size(); i++)
+	{
+		HighlightingRule *rule=&(highlightingRules[i]);
+		
+		QRegExp *expression = &(rule->pattern);
+		int index = rule->lastFound;
+		if(index>-1 && index<startIndex)
+		{
+			rule->lastFound = index = expression->indexIn(text, startIndex);
+		}
+		if ( index>-1 && index<rule1st.startIndex )
+		{
+			rule1st.startIndex=index;
+			rule1st.length=expression->matchedLength();
+			rule1st.rule=i;
+			rule1st.ruleOrder=rule->ruleOrder;
+		}
+		
+		if(index==startIndex) break;
+	}
+	
+	if(rule1st.rule==-1) rule1st.startIndex=-1;
+	
+	return rule1st;
+}
+
+SyntaxHighlighter::Rule1st SyntaxHighlighter::highlight1stBlockRule(const QString & text, int startIndex)
+{
+	Rule1st rule1st;
+	rule1st.startIndex=text.length();
+	rule1st.rule=-1;
+	
+	for(int i=0; i<highlightingBlockRules.size(); i++)
+	{
+		HighlightingBlockRule rule=highlightingBlockRules[i];
+		
+		int index = rule.startPattern.indexIn(text, startIndex);
+		
+		if ( index>-1 && index<rule1st.startIndex )
+		{
+			rule1st.startIndex=index;
+			rule1st.rule=i;
+			rule1st.ruleOrder=rule.ruleOrder;
+		}
+		
+		if(index==startIndex) break;
+	}
+	
+	if(rule1st.rule==-1) rule1st.startIndex=-1;
+	
+	return rule1st;
+}
+
+/**Inserts brackets in position order in blockData->brackets
+ */
+static void insertInOrder(BlockData *blockData, BlockData::Bracket &bracket)
+{
+	if(blockData->brackets.isEmpty()) blockData->brackets.append(bracket);
+	else
+	{
+		int j=0;
+		
+		for(;j<blockData->brackets.size();j++)
+		{
+			if(blockData->brackets[j].pos>bracket.pos)
+			{
+				blockData->brackets.insert(j,bracket);
+				break;
+			}
+		}
+		if(j>=blockData->brackets.size())
+		{
+			blockData->brackets.append(bracket);
+		}
+	}
+}
+
+
+void SyntaxHighlighter::findBrackets(const QString & text, int start, int end, BlockData *blockData)
+{
+	//blockData->brackets.clear();
+	
+	if( end<0 || end>text.length() ) end=text.length();
+	
+	if(start>end) return;
+	
+	for(int i=0; i<highlightingBracketsRules.size(); i++)
+	{
+		HighlightingBlockRule rule=highlightingBracketsRules[i];
+		
+		int startIndex=start;
+		
+		int index = rule.startPattern.indexIn(text, startIndex);
+		
+		while( index>-1 && index<end )
+		{
+			BlockData::Bracket bracket;
+			bracket.pos=index;
+			bracket.type=i;
+			bracket.length=rule.startPattern.matchedLength();
+			bracket.startBracketOk=true;
+			
+			startIndex=index+bracket.length;
+			
+			insertInOrder(blockData, bracket);
+			index = rule.startPattern.indexIn(text, startIndex);
+		}
+		
+		startIndex=start;
+		
+		index = rule.endPattern.indexIn(text, startIndex);
+		
+		
+		
+		while( index>-1 && index<end )
+		{
+			BlockData::Bracket bracket;
+			bracket.pos=index;
+			bracket.type=i;
+			bracket.length=rule.endPattern.matchedLength();
+			bracket.startBracketOk=false;
+			insertInOrder(blockData, bracket);
+			startIndex=index+bracket.length;
+			index = rule.endPattern.indexIn(text, startIndex);
+		}
+	}
+}
+
+
+int SyntaxHighlighter::ruleSetFormat(Rule1st rule1st)
+{
+	HighlightingRule rule=highlightingRules[rule1st.rule];
+	
+	setFormat(rule1st.startIndex, rule1st.length, rule.format);
+	
+	return rule1st.startIndex + rule1st.length;
+}
+
+
+int SyntaxHighlighter::blockRuleSetFormat(const QString & text, Rule1st rule1st)
+{
+	HighlightingBlockRule rule=highlightingBlockRules[rule1st.rule];
+		
+	int endIndex = rule.endPattern.indexIn(text, rule1st.startIndex);
+	int commentLength;
+	if (endIndex == -1)
+	{
+	    setCurrentBlockState(rule1st.rule);
+	    commentLength = text.length() - rule1st.startIndex;
+	    setFormat(rule1st.startIndex, commentLength, rule.format);
+	    return text.length();
+	}
+	else
+	{
+	    commentLength = endIndex - rule1st.startIndex
+	                    + rule.endPattern.matchedLength();
+	    setFormat(rule1st.startIndex, commentLength, rule.format);
+	    
+	    return endIndex+1;
+	}
+}
+
+
+void SyntaxHighlighter::highlightBlock ( const QString & text )
+{
+
+	setCurrentBlockState(-1);
+	
+	int startIndex = 0;
+	
+	//Checks previous block state
+	if (previousBlockState() >= 0)
+	{
+		Rule1st rule1st;
+		rule1st.rule=previousBlockState();
+		rule1st.startIndex=0;
+		
+		startIndex=blockRuleSetFormat(text,rule1st);
+		
+		//TODO: Posible fallo al establecer el estado del bloque
+		
+		if(startIndex==text.length()) return;
+	}
+	
+	//Gets BlockData
+	BlockData *blockData=new BlockData();
+	
+	//Finds first rule to apply. 
+
+	Rule1st rule1st, blockRule1st;
+	
+	//Find initial matches
+	for(int i=0; i<highlightingRules.size(); i++)
+	{
+		HighlightingRule *rule= &(highlightingRules[i]);
+		QRegExp *expression = &(rule->pattern);
+		int index = expression->indexIn(text, startIndex);
+                rule->lastFound = index;
+	}
+
+	rule1st=highlight1stRule( text, startIndex);
+	blockRule1st=highlight1stBlockRule( text, startIndex);
+
+	while(rule1st.rule>=0 || blockRule1st.rule>=0)
+	{
+		if(rule1st.rule>=0 && blockRule1st.rule>=0)
+		{
+			if
+				( 
+					rule1st.startIndex<blockRule1st.startIndex
+					|| 
+					(
+						rule1st.startIndex==blockRule1st.startIndex
+						&&
+						rule1st.ruleOrder<blockRule1st.ruleOrder
+					)
+				)
+			{
+				findBrackets(text, startIndex, rule1st.startIndex, blockData);
+				startIndex=ruleSetFormat(rule1st);
+				rule1st=highlight1stRule( text, startIndex);
+			}
+			else
+			{
+				findBrackets(text, startIndex, blockRule1st.startIndex, blockData);
+				startIndex=blockRuleSetFormat(text,blockRule1st);
+				blockRule1st=highlight1stBlockRule( text, startIndex);
+			}
+		}
+		else if(rule1st.rule>=0)
+		{
+			findBrackets(text, startIndex, rule1st.startIndex, blockData);
+			startIndex=ruleSetFormat(rule1st);
+			rule1st=highlight1stRule( text, startIndex);
+		}
+		else
+		{
+			findBrackets(text, startIndex, blockRule1st.startIndex, blockData);
+			startIndex=blockRuleSetFormat(text,blockRule1st);
+			blockRule1st=highlight1stBlockRule( text, startIndex);
+		}
+	}
+	
+	findBrackets(text,startIndex, -1, blockData);
+	
+	setCurrentBlockUserData(blockData);
+}
+
+/**Search brackets in one QTextBlock.*/
+static BlockData::Bracket *searchBracket(int i, int increment, int &bracketsCount, BlockData *blockData, BlockData::Bracket *bracket1)
+{
+	if(blockData==NULL) return NULL;
+	
+	if(i==-1) i=blockData->brackets.size()-1;
+	
+	for(; i>=0 && i<blockData->brackets.size(); i+=increment)
+	{
+		BlockData::Bracket *bracket=&(blockData->brackets[i]);
+		if(bracket->type==bracket1->type)
+		{
+			if(bracket->startBracketOk!=bracket1->startBracketOk)
+				bracketsCount--;
+			else
+				bracketsCount++;
+			
+			if(bracketsCount==0)
+				return bracket;
+		}
+	}
+	
+	//printf("[searchBracket] bracketsCount=%d\n", bracketsCount);
+	
+	return NULL;
+}
+
+void SyntaxHighlighter::setFormatPairBrackets(QPlainTextEdit *textEdit)
+{
+	QList<QTextEdit::ExtraSelection> selections;
+	
+	textEdit->setExtraSelections(selections);
+	
+	QTextCursor cursor=textEdit->textCursor();
+	QTextBlock block=cursor.block();
+	BlockData *blockData=(BlockData *)block.userData();
+	if(blockData==NULL) return;
+	
+	int pos=cursor.position()-block.position();
+	
+	BlockData::Bracket *bracket1;
+	QTextBlock block_bracket1=block;
+	
+	int i=blockData->brackets.size()-1;
+	for(; i>=0; i--)
+	{
+		BlockData::Bracket *bracket=&(blockData->brackets[i]);
+		if(bracket->pos==pos)
+		{
+			bracket1=bracket;
+			break;
+		}
+	}
+	
+	if(i<0) return;
+	
+	int increment=(bracket1->startBracketOk) ? +1:-1;
+	int bracketsCount=0;
+	//Looks in this block the other bracket
+	BlockData::Bracket *bracket2=NULL;
+	QTextBlock block_bracket2=block;
+	
+	bracket2=searchBracket( i, increment, bracketsCount, blockData, bracket1);
+	
+	{ //Search brackets in other blocks
+		while( bracket2==NULL )
+		{
+			if(increment>0)
+			{
+				block_bracket2=block_bracket2.next();
+				i=0;
+			}
+			else
+			{
+				block_bracket2=block_bracket2.previous();
+				i=-1;
+			}
+			
+			if(!block_bracket2.isValid()) break;
+			
+			blockData=(BlockData *)block_bracket2.userData();
+			/*
+			printf("[Syntax::setFormatPairBrackets] Interno brackets.size=%d\n", blockData->brackets.size());
+			for(int x=0;x<blockData->brackets.size();x++)
+			{
+				BlockData::Bracket *bracket=&(blockData->brackets[x]);
+				printf("[Syntax::setFormatPairBrackets] bracket.pos=%d bracket.type=%d bracket.len=%d bracket.start=%d\n", bracket->pos, bracket->type, bracket->length, (bracket->startBracketOk) );
+			}
+			*/
+			
+			bracket2=searchBracket( i, increment, bracketsCount, blockData, bracket1);
+		}
+		
+		if(bracket2==NULL) return;
+	}
+	
+	pos=cursor.position();
+	
+	QTextEdit::ExtraSelection selection1;
+	
+	cursor.setPosition(pos+bracket1->length, QTextCursor::KeepAnchor);
+	selection1.cursor=cursor;
+	selection1.format=highlightingBracketsRules[bracket1->type].format;
+	
+	pos=bracket2->pos+block_bracket2.position();
+	QTextEdit::ExtraSelection selection2;
+	cursor.setPosition(pos);
+	cursor.setPosition(pos+bracket2->length, QTextCursor::KeepAnchor);
+	selection2.cursor=cursor;
+	selection2.format=highlightingBracketsRules[bracket2->type].format;
+	
+	selections.append(selection1); selections.append(selection2);
+	
+	textEdit->setExtraSelections(selections);
+	
+}
+
+
+
+BlockData::BlockData():QTextBlockUserData()
+{
+}
+
+
new file mode 100644
--- /dev/null
+++ b/gui/src/SyntaxHighlighter.h
@@ -0,0 +1,107 @@
+/* Copyright (C) 2010 P.L. Lucas
+ *
+ * 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.
+ */
+
+#ifndef __SYNTAX_H__
+#define __SYNTAX_H__
+
+#include <QSyntaxHighlighter>
+#include <QTextBlockUserData>
+#include <QVector>
+#include <QPlainTextEdit>
+
+class BlockData:public QTextBlockUserData
+{
+	public:
+	BlockData();
+	
+	struct Bracket
+	{
+		int type;	//Type of bracket
+		int pos;	//Position of bracket
+		int length;	//Number of chars of bracket
+		bool startBracketOk;	//Is it a start or end bracket?
+	};
+	
+	QVector <Bracket> brackets;
+};
+
+class SyntaxHighlighter:public QSyntaxHighlighter
+{
+	Q_OBJECT
+	
+	struct HighlightingRule
+	{
+		QRegExp pattern;
+		QTextCharFormat format;
+		int ruleOrder;
+		int lastFound;
+	};
+	
+	QVector<HighlightingRule> highlightingRules;
+	
+	struct HighlightingBlockRule
+	{
+		QRegExp startPattern, endPattern;
+		QTextCharFormat format;
+		int ruleOrder;
+	};
+	
+	QVector<HighlightingBlockRule> highlightingBlockRules;
+	QVector<HighlightingBlockRule> highlightingBracketsRules;
+	
+	struct Rule1st
+	{
+		int rule;
+		int startIndex;
+		int length;
+		int ruleOrder;
+	};
+	
+	/**1st rule to apply from startIndex.
+	 */
+	Rule1st highlight1stRule(const QString & text, int startIndex);
+	
+	/**1st block rule to apply from startIndex.
+	 */
+	Rule1st highlight1stBlockRule(const QString & text, int startIndex);
+	
+	/** Set format using rule.
+	 */
+	int ruleSetFormat(Rule1st rule);
+	
+	/** Set format using block rule.
+	 */
+	int blockRuleSetFormat(const QString & text, Rule1st rule1st);
+	
+	/** Finds brackets and put them in BlockData.
+	 */
+	void findBrackets(const QString & text, int start, int end, BlockData *blockData);
+	
+	public:
+	
+        SyntaxHighlighter(QObject * parent = 0);
+	bool load(QString file);
+	
+	/**Formats pair of brackets
+	 */
+	void setFormatPairBrackets(QPlainTextEdit *textEdit);
+	
+	protected:
+	void highlightBlock ( const QString & text );
+};
+#endif
new file mode 100644
--- /dev/null
+++ b/gui/src/TerminalCharacterDecoder.cpp
@@ -0,0 +1,247 @@
+/*
+    This file is part of Konsole, an X terminal.
+    
+    Copyright 2006-2008 by Robert Knight <robertknight@gmail.com>
+    
+    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>
+
+// Konsole
+#include "konsole_wcwidth.h"
+
+PlainTextDecoder::PlainTextDecoder()
+ : _output(0)
+ , _includeTrailingWhitespace(true)
+ , _recordLinePositions(false)
+{
+
+}
+void PlainTextDecoder::setTrailingWhitespace(bool enable)
+{
+    _includeTrailingWhitespace = enable;
+}
+bool PlainTextDecoder::trailingWhitespace() const
+{
+    return _includeTrailingWhitespace;
+}
+void PlainTextDecoder::begin(QTextStream* output)
+{
+   _output = output;
+   if (!_linePositions.isEmpty())
+       _linePositions.clear();
+}
+void PlainTextDecoder::end()
+{
+    _output = 0;
+}
+
+void PlainTextDecoder::setRecordLinePositions(bool record)
+{
+    _recordLinePositions = record;
+}
+QList<int> PlainTextDecoder::linePositions() const
+{
+    return _linePositions;
+}
+void PlainTextDecoder::decodeLine(const Character* const characters, int count, LineProperty /*properties*/
+                             )
+{
+    Q_ASSERT( _output );
+
+    if (_recordLinePositions && _output->string())
+    {
+        int pos = _output->string()->count();
+        _linePositions << pos;
+    }
+
+    //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;)
+    {
+        plainText.append( QChar(characters[i].character) );
+        i += qMax(1,konsole_wcwidth(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;
+
+            bool useBold;
+            ColorEntry::FontWeight weight = characters[i].fontWeight(_colorTable);
+            if (weight == ColorEntry::UseCurrentFormat)
+                useBold = _lastRendition & RE_BOLD;
+            else
+                useBold = weight == ColorEntry::Bold;
+            
+            if (useBold)
+                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/src/TerminalCharacterDecoder.h
@@ -0,0 +1,145 @@
+/*
+    This file is part of Konsole, an X terminal.
+    
+    Copyright 2006-2008 by Robert Knight <robertknight@gmail.com>
+    
+    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"
+
+#include <QList>
+
+class QTextStream;
+
+/**
+ * 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 count The number of characters
+     * @param properties Additional properties which affect all characters in the line
+     */
+    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;
+    /** 
+     * Returns of character positions in the output stream
+     * at which new lines where added.  Returns an empty if setTrackLinePositions() is false or if 
+     * the output device is not a string.
+     */
+    QList<int> linePositions() const;
+    /** Enables recording of character positions at which new lines are added.  See linePositions() */
+    void setRecordLinePositions(bool record);
+
+    virtual void begin(QTextStream* output);
+    virtual void end();
+
+    virtual void decodeLine(const Character* const characters,
+                            int count,
+                            LineProperty properties);    
+
+    
+private:
+    QTextStream* _output;
+    bool _includeTrailingWhitespace;
+
+    bool _recordLinePositions;
+    QList<int> _linePositions;
+};
+
+/**
+ * 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/src/TerminalDisplay.cpp
@@ -0,0 +1,2975 @@
+/*
+    This file is part of Konsole, a terminal emulator for KDE.
+    
+    Copyright 2006-2008 by Robert Knight <robertknight@gmail.com>
+    Copyright 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
+    
+    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/QTimer>
+#include <QtGui/QToolTip>
+#include <QtCore/QTextStream>
+
+#include "Filter.h"
+#include "konsole_wcwidth.h"
+#include "ScreenWindow.h"
+#include "TerminalCharacterDecoder.h"
+
+#ifndef loc
+#define loc(X,Y) ((Y)*_columns+(X))
+#endif
+
+#define yMouseScroll 1
+
+#define REPCHAR   "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
+                  "abcdefgjijklmnopqrstuvwxyz" \
+                  "0123456789./+@"
+
+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), ColorEntry( QColor(0xB2,0xB2,0xB2), 1), // Dfore, Dback
+  ColorEntry(QColor(0x00,0x00,0x00), 0), ColorEntry( QColor(0xB2,0x18,0x18), 0), // Black, Red
+  ColorEntry(QColor(0x18,0xB2,0x18), 0), ColorEntry( QColor(0xB2,0x68,0x18), 0), // Green, Yellow
+  ColorEntry(QColor(0x18,0x18,0xB2), 0), ColorEntry( QColor(0xB2,0x18,0xB2), 0), // Blue, Magenta
+  ColorEntry(QColor(0x18,0xB2,0xB2), 0), ColorEntry( QColor(0xB2,0xB2,0xB2), 0), // Cyan, White
+  // intensiv
+  ColorEntry(QColor(0x00,0x00,0x00), 0), ColorEntry( QColor(0xFF,0xFF,0xFF), 1),
+  ColorEntry(QColor(0x68,0x68,0x68), 0), ColorEntry( QColor(0xFF,0x54,0x54), 0),
+  ColorEntry(QColor(0x54,0xFF,0x54), 0), ColorEntry( QColor(0xFF,0xFF,0x54), 0),
+  ColorEntry(QColor(0x54,0x54,0xFF), 0), ColorEntry( QColor(0xFF,0x54,0xFF), 0),
+  ColorEntry(QColor(0x54,0xFF,0xFF), 0), ColorEntry( QColor(0xFF,0xFF,0xFF), 0)
+};
+
+// scroll increment used when dragging selection at top/bottom of window.
+
+// static
+bool TerminalDisplay::_antialiasText = true;
+bool TerminalDisplay::HAVE_TRANSPARENCY = false;
+
+// we use this to force QPainter to display text in LTR mode
+// more information can be found in: http://unicode.org/reports/tr9/ 
+const QChar LTR_OVERRIDE_CHAR( 0x202D );
+
+/* ------------------------------------------------------------------------- */
+/*                                                                           */
+/*                                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 )
+    {
+
+// TODO: Determine if this is an issue.
+//#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::setBackgroundColor(const QColor& color)
+{
+    _colorTable[DEFAULT_BACK_COLOR].color = color;
+    QPalette p = palette();
+      p.setColor( backgroundRole(), color ); 
+      setPalette( p );
+
+      // Avoid propagating the palette change to the scroll bar 
+      _scrollBar->setPalette( QApplication::palette() );  
+
+    update();
+}
+void TerminalDisplay::setForegroundColor(const QColor& color)
+{
+    _colorTable[DEFAULT_FORE_COLOR].color = color;
+
+    update();
+}
+void TerminalDisplay::setColorTable(const ColorEntry table[])
+{
+  for (int i = 0; i < TABLE_COLORS; i++)
+      _colorTable[i] = table[i];
+
+  setBackgroundColor(_colorTable[DEFAULT_BACK_COLOR].color);
+}
+
+/* ------------------------------------------------------------------------- */
+/*                                                                           */
+/*                                   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 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 ( !QFontInfo(font).fixedPitch() )
+  {
+      //kWarning() << "Using an unsupported variable-width font in the terminal.  This may produce display errors.";
+  }
+
+  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)
+,_boldIntense(true)
+,_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)
+,_hasBlinker(false)
+,_cursorBlinking(false)
+,_hasBlinkingCursor(false)
+,_allowBlinkingText(true)
+,_ctrlDrag(true)
+,_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()));
+
+  //KCursor::setAutoHideCursor( this, true );
+  
+  setUsesMouse(true);
+  setColorTable(base_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->setContentsMargins(0, 0, 0, 0);
+
+  setLayout( _gridLayout ); 
+
+  new AutoScrollHandler(this);
+}
+
+TerminalDisplay::~TerminalDisplay()
+{
+  disconnect(_blinkTimer);
+  disconnect(_blinkCursorTimer);
+  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) && _boldIntense )
+        {
+            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;
+    ColorEntry::FontWeight weight = style->fontWeight(_colorTable);    
+    if (weight == ColorEntry::UseCurrentFormat)
+        useBold = ((style->rendition & RE_BOLD) && _boldIntense) || font().bold();
+    else
+        useBold = (weight == ColorEntry::Bold) ? true : false;
+    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);
+    }
+
+    // setup pen
+    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
+    // This was discussed in: http://lists.kde.org/?t=120552223600002&r=1&w=2
+        if (_bidiEnabled)
+            painter.drawText(rect,0,text);
+        else
+            painter.drawText(rect,0,LTR_OVERRIDE_CHAR+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;
+    _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
+void TerminalDisplay::scrollImage(int lines , const QRect& screenWindowRegion)
+{
+    // if the flow control warning is enabled this will interfere with the 
+    // scrolling optimizations and cause artifacts.  the simple solution here
+    // is to just disable the optimization 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) ); 
+
+    // return if there is nothing to do
+    if (    lines == 0 
+         || _image == 0
+         || !region.isValid() 
+         || (region.top() + abs(lines)) >= region.bottom() 
+         || this->_lines <= region.height() ) return;
+
+    // hide terminal size label to prevent it being scrolled
+    if (_resizeWidget && _resizeWidget->isVisible())
+        _resizeWidget->hide();
+
+    // Note:  With Qt 4.4 the left edge of the scrolled area must be at 0
+    // to get the correct (newly exposed) part of the widget repainted.
+    //
+    // The right edge must be before the left edge of the scroll bar to 
+    // avoid triggering a repaint of the entire widget, the distance is 
+    // given by SCROLLBAR_CONTENT_GAP
+    //
+    // Set the QT_FLUSH_PAINT environment variable to '1' before starting the
+    // application to monitor repainting.
+    //
+    int scrollBarWidth = _scrollBar->isHidden() ? 0 : _scrollBar->width();
+    const int SCROLLBAR_CONTENT_GAP = 1;
+    QRect scrollRect;
+    if ( _scrollbarLocation == ScrollBarLeft )
+    {
+        scrollRect.setLeft(scrollBarWidth+SCROLLBAR_CONTENT_GAP);
+        scrollRect.setRight(width());
+    }
+    else
+    {
+        scrollRect.setLeft(0);
+        scrollRect.setRight(width() - scrollBarWidth - SCROLLBAR_CONTENT_GAP);
+    }
+    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
+        scrollRect.setTop(top);
+    }
+    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
+        scrollRect.setTop(top + abs(lines) * _fontHeight); 
+    }
+    scrollRect.setHeight(linesToMove * _fontHeight );
+
+    Q_ASSERT(scrollRect.isValid() && !scrollRect.isEmpty());
+
+    //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 r;
+        if (hotSpot->startLine()==hotSpot->endLine()) {
+            r.setLeft(hotSpot->startColumn());
+            r.setTop(hotSpot->startLine());
+            r.setRight(hotSpot->endColumn());
+            r.setBottom(hotSpot->endLine());
+            region |= imageToWidget(r);;
+        } else {
+            r.setLeft(hotSpot->startColumn());
+            r.setTop(hotSpot->startLine());
+            r.setRight(_columns);
+            r.setBottom(hotSpot->startLine());
+            region |= imageToWidget(r);;
+            for ( int line = hotSpot->startLine()+1 ; line < hotSpot->endLine() ; line++ ) {
+                r.setLeft(0);
+                r.setTop(line);
+                r.setRight(_columns);
+                r.setBottom(line);
+                region |= imageToWidget(r);;
+            }
+            r.setLeft(0);
+            r.setTop(hotSpot->endLine());
+            r.setRight(hotSpot->endColumn());
+            r.setBottom(hotSpot->endLine());
+            region |= imageToWidget(r);;
+        }
+    }
+    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();
+
+  if (!_image) {
+     // Create _image.
+     // The emitted changedContentSizeSignal also leads to getImage being recreated, so do this first.
+     updateImageSize();
+  }
+
+  Character* const newimg = _screenWindow->getImage();
+  int lines = _screenWindow->windowLines();
+  int columns = _screenWindow->windowColumns();
+
+  setScroll( _screenWindow->currentLine() , _screenWindow->lineCount() );
+
+  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( TEXT_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(QString("Size: XXX x XXX"), this);
+        _resizeWidget->setMinimumWidth(_resizeWidget->fontMetrics().width(QString("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 = QString("Size: %1 x %2").arg(_columns).arg(_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(QApplication::cursorFlashTime() / 2);
+  
+  if (!blink && _blinkCursorTimer->isActive()) 
+  {
+    _blinkCursorTimer->stop();
+    if (_cursorBlinking)
+      blinkCursorEvent();
+    else
+      _cursorBlinking = false;
+  }
+}
+
+void TerminalDisplay::setBlinkingTextEnabled(bool blink)
+{
+    _allowBlinkingText = blink;
+
+    if (blink && !_blinkTimer->isActive()) 
+        _blinkTimer->start(TEXT_BLINK_DELAY);
+  
+    if (!blink && _blinkTimer->isActive()) 
+    {
+        _blinkTimer->stop();
+        _blinking = false;
+    }
+}
+
+void TerminalDisplay::focusOutEvent(QFocusEvent*)
+{
+    // trigger a repaint of the cursor so that it is both visible (in case
+    // it was hidden during blinking)
+    // and drawn in a focused out state
+    _cursorBlinking = false;
+    updateCursor();
+
+    _blinkCursorTimer->stop();
+    if (_blinking)
+        blinkEvent();
+
+    _blinkTimer->stop();
+}
+void TerminalDisplay::focusInEvent(QFocusEvent*)
+{
+    if (_hasBlinkingCursor)
+    {
+        _blinkCursorTimer->start();
+    }
+    updateCursor();
+
+    if (_hasBlinker)
+        _blinkTimer->start();
+}
+
+void TerminalDisplay::paintEvent( QPaintEvent* pe )
+{
+  QPainter paint(this);
+
+  foreach (const QRect &rect, (pe->region() & contentsRect()).rects())
+  {
+    drawBackground(paint,rect,palette().background().color(),
+                    true /* use opacity setting */);
+    drawContents(paint, rect);
+  }
+  drawInputMethodPreeditString(paint,preeditRect());
+  paintFilters(paint);
+}
+
+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)
+{
+    // get color of character under mouse and use it to draw
+    // lines for filters
+    QPoint cursorPos = mapFromGlobal(QCursor::pos());
+    int cursorLine;
+    int cursorColumn;
+    int scrollBarWidth = (_scrollbarLocation == ScrollBarLeft) ? _scrollBar->width() : 0;
+
+    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();
+
+        QRegion region;
+        if ( spot->type() == Filter::HotSpot::Link ) {
+            QRect r;
+            if (spot->startLine()==spot->endLine()) {
+                r.setCoords( spot->startColumn()*_fontWidth + 1 + scrollBarWidth, 
+                             spot->startLine()*_fontHeight + 1,
+                             (spot->endColumn()-1)*_fontWidth - 1 + scrollBarWidth, 
+                             (spot->endLine()+1)*_fontHeight - 1 ); 
+                region |= r;
+            } else {
+                r.setCoords( spot->startColumn()*_fontWidth + 1 + scrollBarWidth, 
+                             spot->startLine()*_fontHeight + 1,
+                             (_columns-1)*_fontWidth - 1 + scrollBarWidth, 
+                             (spot->startLine()+1)*_fontHeight - 1 ); 
+                region |= r;
+                for ( int line = spot->startLine()+1 ; line < spot->endLine() ; line++ ) {
+                    r.setCoords( 0*_fontWidth + 1 + scrollBarWidth, 
+                                 line*_fontHeight + 1,
+                                 (_columns-1)*_fontWidth - 1 + scrollBarWidth,
+                                 (line+1)*_fontHeight - 1 ); 
+                    region |= r;
+                }
+                r.setCoords( 0*_fontWidth + 1 + scrollBarWidth,
+                             spot->endLine()*_fontHeight + 1,
+                             (spot->endColumn()-1)*_fontWidth - 1 + scrollBarWidth,
+                             (spot->endLine()+1)*_fontHeight - 1 ); 
+                region |= r;
+            }
+        }
+
+        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 + scrollBarWidth,
+                         line*_fontHeight + 1,
+                         endColumn*_fontWidth - 1 + scrollBarWidth,
+                         (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 ( region.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)
+{
+  QPoint tL  = contentsRect().topLeft();
+  int    tLx = tL.x();
+  int    tLy = tL.y();
+
+  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;
+  QString unistr;
+  unistr.reserve(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;
+
+      // reset our buffer to the maximal size
+      unistr.resize(bufferSize);
+      QChar *disstrU = unistr.data();
+
+      // 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;
+         unistr.resize(p);
+
+         // Create a text scaling matrix for double width and double height lines.
+         QMatrix textScale;
+
+         if (y < _lineProperties.size())
+         {
+            if (_lineProperties[y] & LINE_DOUBLEWIDTH)
+                textScale.scale(2,1);
+
+            if (_lineProperties[y] & LINE_DOUBLEHEIGHT)
+                textScale.scale(1,2);
+         }
+
+         //Apply text scaling matrix.
+         paint.setWorldMatrix(textScale, true);
+
+         //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)    
+         textArea.moveTopLeft( textScale.inverted().map(textArea.topLeft()) );
+         
+         //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.setWorldMatrix(textScale.inverted(), true);
+
+         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;
+    }
+  }
+}
+
+void TerminalDisplay::blinkEvent()
+{
+  if (!_allowBlinkingText) return;
+
+  _blinking = !_blinking;
+
+  //TODO:  Optimize 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
+{
+    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::updateCursor()
+{
+  QRect cursorRect = imageToWidget( QRect(cursorPosition(),QSize(1,1)) ); 
+  update(cursorRect);
+}
+
+void TerminalDisplay::blinkCursorEvent()
+{
+  _cursorBlinking = !_cursorBlinking;
+  updateCursor();
+}
+
+/* ------------------------------------------------------------------------- */
+/*                                                                           */
+/*                                  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()
+{
+  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.
+//
+//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)
+{
+  // 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(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;
+  int scrollBarWidth = (_scrollbarLocation == ScrollBarLeft) ? _scrollBar->width() : 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)
+  {
+    QRegion previousHotspotArea = _mouseOverHotspotArea;
+    _mouseOverHotspotArea = QRegion();
+    QRect r;
+    if (spot->startLine()==spot->endLine()) {
+        r.setCoords( spot->startColumn()*_fontWidth + scrollBarWidth, 
+                     spot->startLine()*_fontHeight,
+                     spot->endColumn()*_fontWidth + scrollBarWidth, 
+                     (spot->endLine()+1)*_fontHeight - 1 ); 
+        _mouseOverHotspotArea |= r;
+    } else {
+        r.setCoords( spot->startColumn()*_fontWidth + scrollBarWidth,
+                     spot->startLine()*_fontHeight,
+                     _columns*_fontWidth - 1 + scrollBarWidth,
+                     (spot->startLine()+1)*_fontHeight ); 
+        _mouseOverHotspotArea |= r;
+        for ( int line = spot->startLine()+1 ; line < spot->endLine() ; line++ ) {
+            r.setCoords( 0*_fontWidth + scrollBarWidth, 
+                         line*_fontHeight,
+                         _columns*_fontWidth + scrollBarWidth,
+                         (line+1)*_fontHeight ); 
+            _mouseOverHotspotArea |= r;
+        }
+        r.setCoords( 0*_fontWidth + scrollBarWidth, 
+                     spot->endLine()*_fontHeight,
+                     spot->endColumn()*_fontWidth + scrollBarWidth, 
+                     (spot->endLine()+1)*_fontHeight ); 
+        _mouseOverHotspotArea |= r;
+    }
+    // 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.boundingRect() );
+    }
+
+    update( _mouseOverHotspotArea | previousHotspotArea );
+  }
+  else if ( !_mouseOverHotspotArea.isEmpty() )
+  {
+        update( _mouseOverHotspotArea );
+        // set hotspot area to an invalid rectangle
+        _mouseOverHotspotArea = QRegion();
+  }
+  
+  // 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() );
+}
+
+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.
+
+  int linesBeyondWidget = 0;
+
+  QRect textBounds(tLx + _leftMargin,
+                     tLy + _topMargin,
+                   _usedColumns*_fontWidth-1,
+                   _usedLines*_fontHeight-1);
+
+  // Adjust position within text area bounds.
+  QPoint oldpos = pos;
+ 
+  pos.setX( qBound(textBounds.left(),pos.x(),textBounds.right()) );
+  pos.setY( qBound(textBounds.top(),pos.y(),textBounds.bottom()) );
+
+  if ( oldpos.y() > textBounds.bottom() ) 
+  {
+      linesBeyondWidget = (oldpos.y()-textBounds.bottom()) / _fontHeight;
+    _scrollBar->setValue(_scrollBar->value()+linesBeyondWidget+1); // scrollforward
+  }
+  if ( oldpos.y() < textBounds.top() )
+  {
+      linesBeyondWidget = (textBounds.top()-oldpos.y()) / _fontHeight;
+    _scrollBar->setValue(_scrollBar->value()-linesBeyondWidget-1); // history
+  }
+
+  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;
+    QChar 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;
+    QChar 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...
+  QChar 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 the terminal program is not interested mouse events
+  // then send the event to the scrollbar if the slider has room to move
+  // or otherwise send simulated up / down key presses to the terminal program
+  // for the benefit of programs such as 'less'
+  if ( _mouseMarks )
+  {
+    bool canScroll = _scrollBar->maximum() > 0;
+      if (canScroll)
+        _scrollBar->event(ev);
+    else
+    {
+        // assume that each Up / Down key event will cause the terminal application
+        // to scroll by one line.  
+        //
+        // to get a reasonable scrolling speed, scroll by one line for every 5 degrees
+        // of mouse wheel rotation.  Mouse wheels typically move in steps of 15 degrees,
+        // giving a scroll of 3 lines
+        int key = ev->delta() > 0 ? Qt::Key_Up : Qt::Key_Down;
+
+        // QWheelEvent::delta() gives rotation in eighths of a degree
+        int wheelDegrees = ev->delta() / 8;
+        int linesToScroll = abs(wheelDegrees) / 5;
+
+        QKeyEvent keyScrollEvent(QEvent::KeyPress,key,Qt::NoModifier);
+
+        for (int i=0;i<linesToScroll;i++)
+            emit keyPressedSignal(&keyScrollEvent);
+    }
+  }
+  else
+  {
+    // terminal program wants notification of mouse activity
+    
+    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());
+    QChar 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 );
+}
+
+
+QChar TerminalDisplay::charClass(QChar qch) const
+{
+    if ( qch.isSpace() ) return ' ';
+
+    if ( qch.isLetterOrNumber() || _wordCharacters.contains(qch, Qt::CaseInsensitive ) )
+    return 'a';
+
+    return qch;
+}
+
+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);
+  if (!text.isEmpty())
+    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 )
+{
+    bool emitKeyPressSignal = true;
+
+    if(event->modifiers() == Qt::ControlModifier)
+    {
+        switch(event->key()) {
+            case Qt::Key_C:
+                copyClipboard();
+                break;
+            case Qt::Key_V:
+                pasteClipboard();
+                break;
+        };
+    } else if ( event->modifiers() == Qt::ShiftModifier ) {
+        bool update = true;
+
+        if ( event->key() == Qt::Key_PageUp )
+        {
+            _screenWindow->scrollBy( ScreenWindow::ScrollPages , -1 );
+        }
+        else if ( event->key() == Qt::Key_PageDown )
+        {
+            _screenWindow->scrollBy( ScreenWindow::ScrollPages , 1 );
+        }
+        else if ( event->key() == Qt::Key_Up )
+        {
+            _screenWindow->scrollBy( ScreenWindow::ScrollLines , -1 );
+        }
+        else if ( event->key() == Qt::Key_Down )
+        {
+            _screenWindow->scrollBy( ScreenWindow::ScrollLines , 1 );
+        }
+        else
+            update = false;
+
+        if ( update )
+        {
+            _screenWindow->setTrackOutput( _screenWindow->atEndOfOutput() );
+            
+            updateLineProperties();
+            updateImage();
+
+            // do not send key press to terminal
+            emitKeyPressSignal = false;
+        }
+    }
+
+    _actSel=0; // Key stroke implies a screen update, so TerminalDisplay won't
+              // know where the current selection is.
+
+    if (_hasBlinkingCursor) 
+    {
+      _blinkCursorTimer->start(QApplication::cursorFlashTime() / 2);
+      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;
+        default:
+            break;
+    }
+
+    return QVariant();
+}
+
+bool TerminalDisplay::handleShortcutOverrideEvent(QKeyEvent* keyEvent)
+{
+    int modifiers = keyEvent->modifiers();
+
+    //  When a possible shortcut combination is pressed, 
+    //  emit the overrideShortcutCheck() signal to allow the host
+    //  to decide whether the terminal should override it or not.
+    if (modifiers != Qt::NoModifier) 
+    {
+        int modifierCount = 0;
+        unsigned int currentModifier = Qt::ShiftModifier;
+
+        while (currentModifier <= Qt::KeypadModifier)
+        {
+            if (modifiers & currentModifier)
+                modifierCount++;
+            currentModifier <<= 1;
+        }
+        if (modifierCount < 2) 
+        {
+            bool override = false;
+            emit overrideShortcutCheck(keyEvent,override);
+            if (override)
+            {
+                keyEvent->accept();
+                return true;
+            }
+        }
+    }
+
+    // Override any of the following shortcuts because
+    // they are needed by the terminal
+    int keyCode = keyEvent->key() | 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 false;
+}
+
+bool TerminalDisplay::event(QEvent* event)
+{
+  bool eventHandled = false;
+  switch (event->type())
+  {
+    case QEvent::ShortcutOverride:
+        eventHandled = handleShortcutOverrideEvent((QKeyEvent*)event);
+        break;
+    case QEvent::PaletteChange:
+    case QEvent::ApplicationPaletteChange:
+        _scrollBar->setPalette( QApplication::palette() );
+        break;
+    default:
+        break;
+  }
+  return eventHandled ? true : QWidget::event(event); 
+}
+
+void TerminalDisplay::setBellMode(int mode)
+{
+  _bellMode=mode;
+}
+
+void TerminalDisplay::enableBell()
+{
+    _allowBell = true;
+}
+
+void TerminalDisplay::bell(const QString& message)
+{
+  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) 
+    {
+      // TODO: This will need added back in at some point
+      //KNotification::beep();
+    } 
+    else if (_bellMode==NotifyBell) 
+    {
+      // TODO: This will need added back in at some point
+      //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(_scrollBar->sizeHint().width(), 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()
+{
+  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, this must be synced with calcGeometry()
+void TerminalDisplay::setSize(int columns, int lines)
+{
+  int scrollBarWidth = _scrollBar->isHidden() ? 0 : _scrollBar->sizeHint().width();
+  int horizontalMargin = 2 * DEFAULT_LEFT_MARGIN;
+  int verticalMargin = 2 * DEFAULT_TOP_MARGIN;
+
+  QSize newSize = QSize( horizontalMargin + scrollBarWidth + (columns * _fontWidth)  ,
+                 verticalMargin + (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( QString("<qt>Output has been "
+                                                "<a href=\"http://en.wikipedia.org/wiki/Flow_control\">suspended</a>"
+                                                " by pressing Ctrl+S."
+                                               "  Press <b>Ctrl+Q</b> to resume.</qt>"),
+                                               this );
+
+            QPalette palette(_outputSuspendedLabel->palette());
+            //KColorScheme::adjustBackground(palette,KColorScheme::NeutralBackground);
+            _outputSuspendedLabel->setPalette(palette);
+            _outputSuspendedLabel->setAutoFillBackground(true);
+            _outputSuspendedLabel->setBackgroundRole(QPalette::Base);
+            _outputSuspendedLabel->setFont(QApplication::font());
+            _outputSuspendedLabel->setContentsMargins(5, 5, 5, 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.
+}
+
+AutoScrollHandler::AutoScrollHandler(QWidget* parent)
+: QObject(parent)
+, _timerId(0)
+{
+    //parent->installEventFilter(this);
+}
+void AutoScrollHandler::timerEvent(QTimerEvent* event)
+{
+    if (event->timerId() != _timerId)
+        return;
+
+    QMouseEvent mouseEvent(    QEvent::MouseMove,
+                              widget()->mapFromGlobal(QCursor::pos()),
+                              Qt::NoButton,
+                              Qt::LeftButton,
+                              Qt::NoModifier);
+
+    QApplication::sendEvent(widget(),&mouseEvent);    
+}
+bool AutoScrollHandler::eventFilter(QObject* watched,QEvent* event)
+{
+    Q_ASSERT( watched == parent() );
+    Q_UNUSED( watched );
+
+    QMouseEvent* mouseEvent = (QMouseEvent*)event;
+    switch (event->type())
+    {
+        case QEvent::MouseMove:
+        {
+            bool mouseInWidget = widget()->rect().contains(mouseEvent->pos());
+
+            if (mouseInWidget)
+            {
+                if (_timerId)
+                    killTimer(_timerId);
+                _timerId = 0;
+            }
+            else
+            {
+                if (!_timerId && (mouseEvent->buttons() & Qt::LeftButton))
+                    _timerId = startTimer(100);
+            }
+                break;
+        }
+        case QEvent::MouseButtonRelease:
+            if (_timerId && (mouseEvent->buttons() & ~Qt::LeftButton))
+            {
+                killTimer(_timerId);
+                _timerId = 0;
+            }
+        break;
+        default:
+        break;
+    };
+
+    return false;
+}
new file mode 100644
--- /dev/null
+++ b/gui/src/TerminalDisplay.h
@@ -0,0 +1,816 @@
+/*
+    Copyright 2007-2008 by Robert Knight <robertknight@gmail.com>
+    Copyright 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
+
+    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"
+
+class QDrag;
+class QDragEnterEvent;
+class QDropEvent;
+class QLabel;
+class QTimer;
+class QEvent;
+class QGridLayout;
+class QKeyEvent;
+class QScrollBar;
+class QShowEvent;
+class QHideEvent;
+class QTimerEvent;
+class QWidget;
+
+class KMenu;
+
+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);
+
+    /** Specifies whether or not text can blink. */
+    void setBlinkingTextEnabled(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;   }
+
+    /**
+     * Specifies whether characters with intense colors should be rendered
+     * as bold. Defaults to true.
+     */
+    void setBoldIntense(bool value) { _boldIntense = value; }
+    /**
+     * Returns true if characters with intense colors are rendered in bold.
+     */
+    bool getBoldIntense() { return _boldIntense; }
+    
+    /**
+     * 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; }
+
+    /**
+     * Sets the status of the BiDi rendering inside the terminal display.
+     * Defaults to disabled.
+     */
+    void setBidiEnabled(bool set) { _bidiEnabled=set; }
+    /**
+     * Returns the status of the BiDi rendering in this widget.
+     */
+    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);
+    /** 
+     * Returns true if the flow control warning box is enabled. 
+     * See outputSuspended() and setFlowControlWarningEnabled()
+     */
+    bool flowControlWarningEnabled() const
+    { return _flowControlWarningEnabled; }
+
+    /** 
+     * 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);
+
+    /** 
+     * Sets the background of the display to the specified color. 
+     * @see setColorTable(), setForegroundColor() 
+     */
+    void setBackgroundColor(const QColor& color);
+
+    /** 
+     * Sets the text of the display to the specified color. 
+     * @see setColorTable(), setBackgroundColor()
+     */
+    void setForegroundColor(const QColor& color);
+
+signals:
+
+    /**
+     * Emitted when the user presses a key whilst the terminal widget has focus.
+     */
+    void keyPressedSignal(QKeyEvent *e);
+
+    /** 
+     * 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(const QPoint& position);
+
+    /**
+     * When a shortcut which is also a valid terminal key sequence is pressed while 
+     * the terminal widget  has focus, this signal is emitted to allow the host to decide 
+     * whether the shortcut should be overridden.  
+     * When the shortcut is overridden, the key sequence will be sent to the terminal emulation instead
+     * and the action associated with the shortcut will not be triggered.
+     *
+     * @p override is set to false by default and the shortcut will be triggered as normal.
+     */
+    void overrideShortcutCheck(QKeyEvent* keyEvent,bool& override);
+
+   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 focusInEvent(QFocusEvent* event);
+    virtual void focusOutEvent(QFocusEvent* event);
+    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;
+
+    // classifies the 'ch' into one of three categories
+    // and returns a character to indicate which category it is in
+    //
+    //     - A space (returns ' ') 
+    //     - Part of a word (returns 'a')
+    //     - Other characters (returns the input character)
+    QChar charClass(QChar ch) 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;
+
+    // redraws the cursor
+    void updateCursor();
+
+    bool handleShortcutOverrideEvent(QKeyEvent* event);
+
+    // 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
+    bool _boldIntense;   // Whether intense colors should be rendered with bold font
+
+    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 _allowBlinkingText;  // allow text to blink
+    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;
+    QRegion _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 TEXT_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;
+    }
+};
+
+class AutoScrollHandler : public QObject
+{
+Q_OBJECT
+
+public:
+    AutoScrollHandler(QWidget* parent);
+protected:
+    virtual void timerEvent(QTimerEvent* event);
+    virtual bool eventFilter(QObject* watched,QEvent* event);
+private:
+    QWidget* widget() const { return static_cast<QWidget*>(parent()); }
+    int _timerId;
+};
+
+
+#endif // TERMINALDISPLAY_H
new file mode 100644
--- /dev/null
+++ b/gui/src/VariablesDockWidget.cpp
@@ -0,0 +1,168 @@
+#include "VariablesDockWidget.h"
+#include <QHBoxLayout>
+#include <QVBoxLayout>
+#include <QPushButton>
+
+VariablesDockWidget::VariablesDockWidget(QWidget *parent)
+    : QDockWidget(parent) {
+    setObjectName("VariablesDockWidget");
+    construct();
+}
+
+void VariablesDockWidget::construct() {
+    m_updateSemaphore = new QSemaphore(1);
+    QStringList headerLabels;
+    headerLabels << tr("Name") << tr("Type") << tr("Value");
+    m_variablesTreeWidget = new QTreeWidget(this);
+    m_variablesTreeWidget->setHeaderHidden(false);
+    m_variablesTreeWidget->setHeaderLabels(headerLabels);
+    QVBoxLayout *layout = new QVBoxLayout();
+
+    setWindowTitle(tr("Workspace"));
+    setWidget(new QWidget());
+
+    layout->addWidget(m_variablesTreeWidget);
+    QWidget *buttonBar = new QWidget(this);
+    layout->addWidget(buttonBar);
+
+        QHBoxLayout *buttonBarLayout = new QHBoxLayout();
+        QPushButton *saveWorkspaceButton = new QPushButton(tr("Save"), buttonBar);
+        QPushButton *loadWorkspaceButton = new QPushButton(tr("Load"), buttonBar);
+        QPushButton *clearWorkspaceButton = new QPushButton(tr("Clear"), buttonBar);
+        buttonBarLayout->addWidget(saveWorkspaceButton);
+        buttonBarLayout->addWidget(loadWorkspaceButton);
+        buttonBarLayout->addWidget(clearWorkspaceButton);
+        buttonBarLayout->setMargin(2);
+        buttonBar->setLayout(buttonBarLayout);
+
+    layout->setMargin(2);
+    widget()->setLayout(layout);
+
+    connect(saveWorkspaceButton, SIGNAL(clicked()), this, SLOT(emitSaveWorkspace()));
+    connect(loadWorkspaceButton, SIGNAL(clicked()), this, SLOT(emitLoadWorkspace()));
+    connect(clearWorkspaceButton, SIGNAL(clicked()), this, SLOT(emitClearWorkspace()));
+
+    QTreeWidgetItem *treeWidgetItem = new QTreeWidgetItem();
+    treeWidgetItem->setData(0, 0, QString(tr("Local")));
+    m_variablesTreeWidget->insertTopLevelItem(0, treeWidgetItem);
+
+    treeWidgetItem = new QTreeWidgetItem();
+    treeWidgetItem->setData(0, 0, QString(tr("Global")));
+    m_variablesTreeWidget->insertTopLevelItem(1, treeWidgetItem);
+
+    treeWidgetItem = new QTreeWidgetItem();
+    treeWidgetItem->setData(0, 0, QString(tr("Persistent")));
+    m_variablesTreeWidget->insertTopLevelItem(2, treeWidgetItem);
+
+    treeWidgetItem = new QTreeWidgetItem();
+    treeWidgetItem->setData(0, 0, QString(tr("Hidden")));
+    m_variablesTreeWidget->insertTopLevelItem(3, treeWidgetItem);
+
+    m_variablesTreeWidget->expandAll();
+    m_variablesTreeWidget->setAlternatingRowColors(true);
+    m_variablesTreeWidget->setAnimated(true);    
+}
+
+void VariablesDockWidget::updateTreeEntry(QTreeWidgetItem *treeItem, SymbolRecord symbolRecord) {
+    treeItem->setData(0, 0, QString(symbolRecord.name().c_str()));
+    treeItem->setData(1, 0, QString(symbolRecord.varval().type_name().c_str()));
+    treeItem->setData(2, 0, OctaveLink::octaveValueAsQString(symbolRecord.varval()));
+}
+
+void VariablesDockWidget::setVariablesList(QList<SymbolRecord> symbolTable) {
+    m_updateSemaphore->acquire();
+    // Split the symbol table into its different scopes.
+    QList<SymbolRecord> localSymbolTable;
+    QList<SymbolRecord> globalSymbolTable;
+    QList<SymbolRecord> persistentSymbolTable;
+    QList<SymbolRecord> hiddenSymbolTable;
+
+    foreach(SymbolRecord symbolRecord, symbolTable) {
+        // It's true that being global or hidden includes it's can mean it's also locally visible,
+        // but we want to distinguish that here.
+        if(symbolRecord.is_local() && !symbolRecord.is_global() && !symbolRecord.is_hidden()) {
+            localSymbolTable.append(symbolRecord);
+        }
+
+        if(symbolRecord.is_global()) {
+            globalSymbolTable.append(symbolRecord);
+        }
+
+        if(symbolRecord.is_persistent()) {
+            persistentSymbolTable.append(symbolRecord);
+        }
+
+        if(symbolRecord.is_hidden()) {
+            hiddenSymbolTable.append(symbolRecord);
+        }
+    }
+
+    updateScope(0, localSymbolTable);
+    updateScope(1, globalSymbolTable);
+    updateScope(2, persistentSymbolTable);
+    updateScope(3, hiddenSymbolTable);
+    m_updateSemaphore->release();
+}
+
+void VariablesDockWidget::updateScope(int topLevelItemIndex, QList<SymbolRecord> symbolTable) {
+    // This method may be a little bit confusing; variablesList is a complete list of all
+    // variables that are in the workspace currently.
+    QTreeWidgetItem *topLevelItem = m_variablesTreeWidget->topLevelItem(topLevelItemIndex);
+
+    // First we check, if any variables that exist in the model tree have to be updated
+    // or created. So we walk the variablesList check against the tree.
+    foreach(SymbolRecord symbolRecord, symbolTable) {
+        int childCount = topLevelItem->childCount();
+        bool alreadyExists = false;
+        QTreeWidgetItem *child;
+
+        // Search for the corresponding item in the tree. If it has been found, child
+        // will contain the appropriate QTreeWidgetItem* pointing at it.
+        for(int i = 0; i < childCount; i++) {
+            child = topLevelItem->child(i);
+            if(child->data(0, 0).toString() == QString(symbolRecord.name().c_str())) {
+                alreadyExists = true;
+                break;
+            }
+        }
+
+        // If it already exists, just update it.
+        if(alreadyExists) {
+            updateTreeEntry(child, symbolRecord);
+        } else {
+            // It does not exist, so create a new one and set the right values.
+            child = new QTreeWidgetItem();
+            updateTreeEntry(child, symbolRecord);
+            topLevelItem->addChild(child);
+        }
+    }
+
+    // Check the tree against the list for deleted variables.
+    for(int i = 0; i < topLevelItem->childCount(); i++) {
+        bool existsInVariableList = false;
+        QTreeWidgetItem *child = topLevelItem->child(i);
+        foreach(SymbolRecord symbolRecord, symbolTable) {
+            if(QString(symbolRecord.name().c_str()) == child->data(0, 0).toString()) {
+                existsInVariableList = true;
+            }
+        }
+
+        if(!existsInVariableList) {
+            topLevelItem->removeChild(child);
+            delete child;
+            i--;
+        }
+    }
+}
+
+void VariablesDockWidget::emitSaveWorkspace() {
+    emit saveWorkspace();
+}
+
+void VariablesDockWidget::emitLoadWorkspace() {
+    emit loadWorkspace();
+}
+
+void VariablesDockWidget::emitClearWorkspace() {
+    emit clearWorkspace();
+}
new file mode 100644
--- /dev/null
+++ b/gui/src/VariablesDockWidget.h
@@ -0,0 +1,34 @@
+#ifndef VARIABLESDOCKWIDGET_H
+#define VARIABLESDOCKWIDGET_H
+
+#include <QDockWidget>
+#include <QTreeWidget>
+#include <QSemaphore>
+#include "OctaveLink.h"
+
+class VariablesDockWidget : public QDockWidget
+{
+    Q_OBJECT
+public:
+    VariablesDockWidget(QWidget *parent = 0);
+    void setVariablesList(QList<SymbolRecord> symbolTable);
+
+signals:
+    void saveWorkspace();
+    void loadWorkspace();
+    void clearWorkspace();
+
+private slots:
+    void emitSaveWorkspace();
+    void emitLoadWorkspace();
+    void emitClearWorkspace();
+
+private:
+    void construct();
+    void updateTreeEntry(QTreeWidgetItem *treeItem, SymbolRecord symbolRecord);
+    void updateScope(int topLevelItemIndex, QList<SymbolRecord> symbolTable);
+    QTreeWidget *m_variablesTreeWidget;
+    QSemaphore *m_updateSemaphore;
+};
+
+#endif // VARIABLESDOCKWIDGET_H
new file mode 100644
--- /dev/null
+++ b/gui/src/Vt102Emulation.cpp
@@ -0,0 +1,1214 @@
+/*
+    This file is part of Konsole, an X terminal.
+    
+    Copyright 2007-2008 by Robert Knight <robert.knight@gmail.com>
+    Copyright 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
+
+    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"
+
+
+// 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
+
+#if defined(HAVE_XKB)
+    void scrolllock_set_off();
+    void scrolllock_set_on();
+#endif
+
+// Standard 
+#include <stdio.h>
+#include <unistd.h>
+#include <assert.h>
+
+// Qt
+#include <QtCore/QEvent>
+#include <QtGui/QKeyEvent>
+#include <QtCore/QByteRef>
+
+// Konsole
+#include "KeyboardTranslator.h"
+#include "Screen.h"
+
+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()
+{
+  resetTokenizer();
+  resetModes();
+  resetCharset(0);
+  _screen[0]->reset();
+  resetCharset(1);
+  _screen[1]->reset();
+  setCodec(LocaleCodec);
+ 
+  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 (processToken)
+
+   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 window/terminal attribute commands 
+                  of the form <ESC>`]' {Pn} `;' {Text} <BEL>
+                  (Note that these are handled differently to the other formats)
+
+   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_CONSTRUCT(T,A,N) ( ((((int)N) & 0xffff) << 16) | ((((int)A) & 0xff) << 8) | (((int)T) & 0xff) )
+
+#define TY_CHR(   )     TY_CONSTRUCT(0,0,0)
+#define TY_CTL(A  )     TY_CONSTRUCT(1,A,0)
+#define TY_ESC(A  )     TY_CONSTRUCT(2,A,0)
+#define TY_ESC_CS(A,B)  TY_CONSTRUCT(3,A,B)
+#define TY_ESC_DE(A  )  TY_CONSTRUCT(4,A,0)
+#define TY_CSI_PS(A,N)  TY_CONSTRUCT(5,A,N)
+#define TY_CSI_PN(A  )  TY_CONSTRUCT(6,A,0)
+#define TY_CSI_PR(A,N)  TY_CONSTRUCT(7,A,N)
+
+#define TY_VT52(A)    TY_CONSTRUCT(8,A,0)
+#define TY_CSI_PG(A)  TY_CONSTRUCT(9,A,0)
+#define TY_CSI_PE(A)  TY_CONSTRUCT(10,A,0)
+
+#define MAX_ARGUMENT 4096
+
+// Tokenizer --------------------------------------------------------------- --
+
+/* The tokenizer's state
+
+   The state is represented by the buffer (tokenBuffer, tokenBufferPos),
+   and accompanied by decoded arguments kept in (argv,argc).
+   Note that they are kept internal in the tokenizer.
+*/
+
+void Vt102Emulation::resetTokenizer()
+{
+  tokenBufferPos = 0; 
+  argc = 0; 
+  argv[0] = 0; 
+  argv[1] = 0;
+}
+
+void Vt102Emulation::addDigit(int digit)
+{
+  if (argv[argc] < MAX_ARGUMENT)
+      argv[argc] = 10*argv[argc] + digit;
+}
+
+void Vt102Emulation::addArgument()
+{
+  argc = qMin(argc+1,MAXARGS-1);
+  argv[argc] = 0;
+}
+
+void Vt102Emulation::addToCurrentToken(int cc)
+{
+  tokenBuffer[tokenBufferPos] = cc;
+  tokenBufferPos = qMin(tokenBufferPos+1,MAX_TOKEN_LENGTH-1);
+}
+
+// Character Class flags used while decoding
+
+#define CTL  1  // Control character
+#define CHR  2  // Printable character
+#define CPN  4  // TODO: Document me 
+#define DIG  8  // Digit
+#define SCS 16  // TODO: Document me  
+#define GRP 32  // TODO: Document me
+#define CPS 64  // Character which indicates end of window resize
+                // escape sequence '\e[8;<row>;<col>t'
+
+void Vt102Emulation::initTokenizer()
+{ 
+  int i; 
+  quint8* s;
+  for(i = 0;i < 256; ++i) 
+    charClass[i] = 0;
+  for(i = 0;i < 32; ++i) 
+    charClass[i] |= CTL;
+  for(i = 32;i < 256; ++i) 
+    charClass[i] |= CHR;
+  for(s = (quint8*)"@ABCDGHILMPSTXZcdfry"; *s; ++s) 
+    charClass[*s] |= CPN;
+  // resize = \e[8;<row>;<col>t
+  for(s = (quint8*)"t"; *s; ++s) 
+    charClass[*s] |= CPS;
+  for(s = (quint8*)"0123456789"; *s; ++s) 
+    charClass[*s] |= DIG;
+  for(s = (quint8*)"()+*%"; *s; ++s) 
+    charClass[*s] |= SCS;
+  for(s = (quint8*)"()+*#[]%"; *s; ++s) 
+    charClass[*s] |= GRP;
+
+  resetTokenizer();
+}
+
+/* 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 'charClass').
+   
+   - 'cc' is the current character
+   - 's' is a pointer to the start of the token buffer
+   - 'p' is the current position within the token buffer 
+
+   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 && (charClass[s[(L)]] & (C)) == (C))
+#define eec(C)     (p >=  3  && cc == (C))
+#define ees(C)     (p >=  3  && cc < 256 && (charClass[cc] & (C)) == (C))
+#define eps(C)     (p >=  3  && s[2] != '?' && s[2] != '!' && s[2] != '>' && cc < 256 && (charClass[cc] & (C)) == (C))
+#define epp( )     (p >=  3  && s[2] == '?')
+#define epe( )     (p >=  3  && s[2] == '!')
+#define egt( )     (p >=  3  && s[2] == '>')
+#define Xpe        (tokenBufferPos >= 2 && tokenBuffer[1] == ']')
+#define Xte        (Xpe      && cc ==  7 )
+#define ces(C)     (cc < 256 && (charClass[cc] & (C)) == (C) && !Xte)
+
+#define ESC 27
+#define CNTL(c) ((c)-'@')
+
+// process an incoming unicode character
+void Vt102Emulation::receiveChar(int cc)
+{ 
+  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 resetTokenizer() 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) 
+        resetTokenizer(); //VT100: CAN or SUB
+    if (cc != ESC)    
+    { 
+        processToken(TY_CTL(cc+'@' ),0,0); 
+        return; 
+    }
+  }
+  // advance the state
+  addToCurrentToken(cc); 
+
+  int* s = tokenBuffer;
+  int  p = tokenBufferPos;
+
+  if (getMode(MODE_Ansi)) 
+  {
+    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         ) { processWindowAttributeChange(); resetTokenizer(); return; }
+    if (Xpe         ) { return; }
+    if (lec(3,2,'?')) { return; }
+    if (lec(3,2,'>')) { return; }
+    if (lec(3,2,'!')) { return; }
+    if (lun(       )) { processToken( TY_CHR(), applyCharset(cc), 0);   resetTokenizer(); return; }
+    if (lec(2,0,ESC)) { processToken( TY_ESC(s[1]), 0, 0);              resetTokenizer(); return; }
+    if (les(3,1,SCS)) { processToken( TY_ESC_CS(s[1],s[2]), 0, 0);      resetTokenizer(); return; }
+    if (lec(3,1,'#')) { processToken( TY_ESC_DE(s[2]), 0, 0);           resetTokenizer(); return; }
+    if (eps(    CPN)) { processToken( TY_CSI_PN(cc), argv[0],argv[1]);  resetTokenizer(); return; }
+
+    // resize = \e[8;<row>;<col>t
+    if (eps(CPS)) 
+    { 
+        processToken( TY_CSI_PS(cc, argv[0]), argv[1], argv[2]);   
+        resetTokenizer(); 
+        return; 
+    }
+
+    if (epe(   )) { processToken( TY_CSI_PE(cc), 0, 0); resetTokenizer(); return; }
+    if (ees(DIG)) { addDigit(cc-'0'); return; }
+    if (eec(';')) { addArgument();    return; }
+    for (int i=0;i<=argc;i++)
+    {
+        if (epp())  
+            processToken( TY_CSI_PR(cc,argv[i]), 0, 0);
+        else if (egt())   
+            processToken( 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;
+            processToken( 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;
+            processToken( TY_CSI_PS(cc, argv[i-2]), COLOR_SPACE_256, argv[i]);
+        }
+        else
+            processToken( TY_CSI_PS(cc,argv[i]), 0, 0);
+    }
+    resetTokenizer();
+  }
+  else 
+  {
+    // VT52 Mode
+    if (lec(1,0,ESC))                                                      
+        return;
+    if (les(1,0,CHR)) 
+    { 
+        processToken( TY_CHR(), s[0], 0); 
+        resetTokenizer(); 
+        return; 
+    }
+    if (lec(2,1,'Y'))                                                      
+        return;
+    if (lec(3,1,'Y'))                                                      
+        return;
+    if (p < 4) 
+    { 
+        processToken( TY_VT52(s[1] ), 0, 0); 
+        resetTokenizer(); 
+        return; 
+    }
+    processToken( TY_VT52(s[1]), s[2], s[3]); 
+    resetTokenizer(); 
+    return;
+  }
+}
+void Vt102Emulation::processWindowAttributeChange()
+{
+  // Describes the window or terminal session attribute to change
+  // See Session::UserTitleChange for possible values
+  int attributeToChange = 0;
+  int i;
+  for (i = 2; i < tokenBufferPos     && 
+              tokenBuffer[i] >= '0'  && 
+              tokenBuffer[i] <= '9'; i++)
+  {
+    attributeToChange = 10 * attributeToChange + (tokenBuffer[i]-'0');
+  }
+
+  if (tokenBuffer[i] != ';') 
+  { 
+    reportDecodingError(); 
+    return; 
+  }
+  
+  QString newValue;
+  newValue.reserve(tokenBufferPos-i-2);
+  for (int j = 0; j < tokenBufferPos-i-2; j++)
+    newValue[j] = tokenBuffer[i+1+j];
+ 
+  _pendingTitleUpdates[attributeToChange] = newValue;
+  _titleUpdateTimer->start(20);
+}
+
+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::processToken(int token, int p, int q)
+{
+  switch (token)
+  {
+
+    case TY_CHR(         ) : _currentScreen->displayCharacter     (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->tab                  (          ); 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->toStartOfLine        (          ); 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->displayCharacter     (    0x2592); break; //VT100
+    case TY_CTL('Y'      ) : /* EM : ignored                      */ break;
+    case TY_CTL('Z'      ) : _currentScreen->displayCharacter     (    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 /* columns */, 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('J',      3) : clearHistory();                            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->tab                  (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->backtab              (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) :          setMode      (MODE_132Columns);break; //VT100
+    case TY_CSI_PR('l',   3) :        resetMode      (MODE_132Columns);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',  40) :         setMode(MODE_Allow132Columns ); break; // XTERM
+    case TY_CSI_PR('l',  40) :       resetMode(MODE_Allow132Columns ); break; // XTERM
+
+    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', 1034) : /* IGNORED: 8bitinput activation     */ 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: 
+        reportDecodingError();    
+        break;
+  };
+}
+
+void Vt102Emulation::clearScreenAndSetColumns(int columnCount)
+{
+    setImageSize(_currentScreen->getLines(),columnCount); 
+    clearEntireScreen();
+    setDefaultMargins(); 
+    _currentScreen->setCursorYX(0,0);
+}
+
+void Vt102Emulation::sendString(const char* s , int length)
+{
+  if ( length >= 0 )
+    emit sendData(s,length);
+  else
+    emit sendData(s,strlen(s));
+}
+
+void Vt102Emulation::reportCursorPosition()
+{ 
+  char tmp[20];
+  sprintf(tmp,"\033[%d;%dR",_currentScreen->getCursorY()+1,_currentScreen->getCursorX()+1);
+  sendString(tmp);
+}
+
+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.
+}
+
+void Vt102Emulation::reportAnswerBack()
+{
+  // FIXME - Test this with VTTEST
+  // This is really obsolete VT100 stuff.
+  const char* ANSWER_BACK = "";
+  sendString(ANSWER_BACK);
+}
+
+/*!
+    `cx',`cy' are 1-based.
+    `eventType' 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 )
+{ 
+  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
+
+  char command[20];
+  sprintf(command,"\033[M%c%c%c",cb+0x20,cx+0x20,cy+0x20);
+  sendString(command);
+}
+
+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;
+    if (getMode(MODE_AppKeyPad) && (modifiers & Qt::KeypadModifier)) 
+        states |= KeyboardTranslator::ApplicationKeypadState;
+
+    // check flow control state
+    if (modifiers & Qt::ControlModifier)
+    {
+        if (event->key() == Qt::Key_S)
+            emit flowControlKeyPressed(true);
+        else if (event->key() == Qt::Key_Q)
+            emit flowControlKeyPressed(false);
+    }
+
+    // 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 += eraseChar();
+
+            // 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 =  QString("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);
+}
+
+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();
+}
+
+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()
+{
+  // MODE_Allow132Columns is not reset here
+  // to match Xterm's behaviour (see Xterm's VTReset() function)
+
+  resetMode(MODE_132Columns); saveMode(MODE_132Columns);
+  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);
+  resetMode(MODE_AppCuKeys);  saveMode(MODE_AppCuKeys);
+  resetMode(MODE_AppKeyPad);  saveMode(MODE_AppKeyPad);
+  resetMode(MODE_NewLine);
+  setMode(MODE_Ansi);
+}
+
+void Vt102Emulation::setMode(int m)
+{
+  _currentModes.mode[m] = true;
+  switch (m)
+  {
+    case MODE_132Columns:
+        if (getMode(MODE_Allow132Columns))
+            clearScreenAndSetColumns(132);
+        else
+            _currentModes.mode[m] = false;
+        break;
+    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)
+{
+  _currentModes.mode[m] = false;
+  switch (m)
+  {
+    case MODE_132Columns:
+        if (getMode(MODE_Allow132Columns))
+            clearScreenAndSetColumns(80);
+        break;
+    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)
+{
+  _savedModes.mode[m] = _currentModes.mode[m];
+}
+
+void Vt102Emulation::restoreMode(int m)
+{
+  if (_savedModes.mode[m]) 
+      setMode(m); 
+  else 
+      resetMode(m);
+}
+
+bool Vt102Emulation::getMode(int m)
+{
+  return _currentModes.mode[m];
+}
+
+char Vt102Emulation::eraseChar() const
+{
+  KeyboardTranslator::Entry entry = _keyTranslator->findEntry(
+                                            Qt::Key_Backspace,
+                                            0,
+                                            0);
+  if ( entry.text().count() > 0 )
+      return entry.text()[0];
+  else
+      return '\b';
+}
+
+// print contents of the scan buffer
+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::reportDecodingError()
+{
+  if (tokenBufferPos == 0 || ( tokenBufferPos == 1 && (tokenBuffer[0] & 0xff) >= 32) ) 
+    return;
+  printf("Undecodable sequence: "); 
+  hexdump(tokenBuffer,tokenBufferPos); 
+  printf("\n");
+}
+
new file mode 100644
--- /dev/null
+++ b/gui/src/Vt102Emulation.h
@@ -0,0 +1,186 @@
+/*
+    This file is part of Konsole, an X terminal.
+    
+    Copyright 2007-2008 by Robert Knight <robertknight@gmail.com>
+    Copyright 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
+
+    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)   // Mode #1
+#define MODE_AppCuKeys       (MODES_SCREEN+1)   // Application cursor keys (DECCKM)
+#define MODE_AppKeyPad       (MODES_SCREEN+2)   // 
+#define MODE_Mouse1000       (MODES_SCREEN+3)   // Send mouse X,Y position on press and release
+#define MODE_Mouse1001       (MODES_SCREEN+4)   // Use Hilight mouse tracking
+#define MODE_Mouse1002       (MODES_SCREEN+5)   // Use cell motion mouse tracking
+#define MODE_Mouse1003       (MODES_SCREEN+6)   // Use all motion mouse tracking 
+#define MODE_Ansi            (MODES_SCREEN+7)   // Use US Ascii for character sets G0-G3 (DECANM) 
+#define MODE_132Columns      (MODES_SCREEN+8)   // 80 <-> 132 column mode switch (DECCOLM)
+#define MODE_Allow132Columns (MODES_SCREEN+9)   // Allow DECCOLM mode
+#define MODE_total           (MODES_SCREEN+10)
+
+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 from Emulation
+  virtual void clearEntireScreen();
+  virtual void reset();
+  virtual char eraseChar() const;
+  
+public slots: 
+  // reimplemented from Emulation 
+  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 from Emulation
+  virtual void setMode(int mode);
+  virtual void resetMode(int mode);
+  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
+  // (except MODE_Allow132Columns)
+  void resetModes();
+
+  void resetTokenizer();
+  #define MAX_TOKEN_LENGTH 80
+  void addToCurrentToken(int cc);
+  int tokenBuffer[MAX_TOKEN_LENGTH]; //FIXME: overflow?
+  int tokenBufferPos;
+#define MAXARGS 15
+  void addDigit(int dig);
+  void addArgument();
+  int argv[MAXARGS];
+  int argc;
+  void initTokenizer();
+
+  // Set of flags for each of the ASCII characters which indicates
+  // what category they fall into (printable character, control, digit etc.)
+  // for the purposes of decoding terminal output
+  int charClass[256];
+
+  void reportDecodingError(); 
+
+  void processToken(int code, int p, int q);
+  void processWindowAttributeChange();
+
+  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];
+
+  class TerminalState
+  {
+  public:
+    // Initializes all modes to false
+    TerminalState()
+    { memset(&mode,false,MODE_total * sizeof(bool)); }
+
+    bool mode[MODE_total];
+  };
+
+  TerminalState _currentModes;
+  TerminalState _savedModes;
+
+  //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/src/konsole_export.h
@@ -0,0 +1,67 @@
+/*
+    This file is part of the KDE project
+    Copyright (C) 2009 Patrick Spendrin <ps_ml@gmx.de>
+
+    This library 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 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 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 KONSOLE_EXPORT_H
+#define KONSOLE_EXPORT_H
+
+/* needed for KDE_EXPORT macros */
+//#include <kdemacros.h>
+#include <QtCore/qglobal.h>
+#define KDE_EXPORT
+#define KDE_IMPORT
+
+#ifndef KONSOLEPRIVATE_EXPORT
+# if defined(MAKE_KONSOLEPRIVATE_LIB)
+   /* We are building this library */
+#  define KONSOLEPRIVATE_EXPORT KDE_EXPORT
+# else
+   /* We are using this library */
+#  define KONSOLEPRIVATE_EXPORT KDE_IMPORT
+# endif
+#endif
+
+#include <iostream>
+//#define kWarning(x) std::cout
+
+#include <stdio.h>
+
+//#define i18n 
+inline QString i18n(char *buff,...)
+{
+  char msg[2048];
+    va_list arglist;
+
+    va_start(arglist,buff);
+
+    snprintf(msg,2048,buff, arglist);
+
+    va_end(arglist);
+
+    return QString(msg);
+}
+
+#define i18nc 
+
+
+//#define KDE_fseek ::fseek
+//#define KDE_lseek ::lseek
+
+
+#endif
new file mode 100644
--- /dev/null
+++ b/gui/src/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/src/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/src/kprocess.cpp
@@ -0,0 +1,345 @@
+/*
+    This file is part of the KDE libraries
+
+    Copyright (C) 2007 Oswald Buddenhagen <ossi@kde.org>
+
+    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 "kprocess_p.h"
+
+#include <qfile.h>
+
+#ifdef Q_OS_WIN
+# include <windows.h>
+#else
+# include <unistd.h>
+# include <errno.h>
+#endif
+
+#ifndef Q_OS_WIN
+# define STD_OUTPUT_HANDLE 1
+# define STD_ERROR_HANDLE 2
+#endif
+
+#ifdef _WIN32_WCE
+#include <stdio.h>
+#endif
+
+void KProcessPrivate::writeAll(const QByteArray &buf, int fd)
+{
+#ifdef Q_OS_WIN
+#ifndef _WIN32_WCE
+    HANDLE h = GetStdHandle(fd);
+    if (h) {
+        DWORD wr;
+        WriteFile(h, buf.data(), buf.size(), &wr, 0);
+    }
+#else
+    fwrite(buf.data(), 1, buf.size(), (FILE*)fd);
+#endif
+#else
+    int off = 0;
+    do {
+        int ret = ::write(fd, buf.data() + off, buf.size() - off);
+        if (ret < 0) {
+            if (errno != EINTR)
+                return;
+        } else {
+            off += ret;
+        }
+    } while (off < buf.size());
+#endif
+}
+
+void KProcessPrivate::forwardStd(KProcess::ProcessChannel good, int fd)
+{
+    Q_Q(KProcess);
+
+    QProcess::ProcessChannel oc = q->readChannel();
+    q->setReadChannel(good);
+    writeAll(q->readAll(), fd);
+    q->setReadChannel(oc);
+}
+
+void KProcessPrivate::_k_forwardStdout()
+{
+#ifndef _WIN32_WCE
+    forwardStd(KProcess::StandardOutput, STD_OUTPUT_HANDLE);
+#else
+    forwardStd(KProcess::StandardOutput, (int)stdout);
+#endif
+}
+
+void KProcessPrivate::_k_forwardStderr()
+{
+#ifndef _WIN32_WCE
+    forwardStd(KProcess::StandardError, STD_ERROR_HANDLE);
+#else
+    forwardStd(KProcess::StandardError, (int)stderr);
+#endif
+}
+
+/////////////////////////////
+// public member functions //
+/////////////////////////////
+
+KProcess::KProcess(QObject *parent) :
+    QProcess(parent),
+    d_ptr(new KProcessPrivate)
+{
+    d_ptr->q_ptr = this;
+    setOutputChannelMode(ForwardedChannels);
+}
+
+KProcess::KProcess(KProcessPrivate *d, QObject *parent) :
+    QProcess(parent),
+    d_ptr(d)
+{
+    d_ptr->q_ptr = this;
+    setOutputChannelMode(ForwardedChannels);
+}
+
+KProcess::~KProcess()
+{
+    delete d_ptr;
+}
+
+void KProcess::setOutputChannelMode(OutputChannelMode mode)
+{
+    Q_D(KProcess);
+
+    d->outputChannelMode = mode;
+    disconnect(this, SIGNAL(readyReadStandardOutput()));
+    disconnect(this, SIGNAL(readyReadStandardError()));
+    switch (mode) {
+    case OnlyStdoutChannel:
+        connect(this, SIGNAL(readyReadStandardError()), SLOT(_k_forwardStderr()));
+        break;
+    case OnlyStderrChannel:
+        connect(this, SIGNAL(readyReadStandardOutput()), SLOT(_k_forwardStdout()));
+        break;
+    default:
+        QProcess::setProcessChannelMode((ProcessChannelMode)mode);
+        return;
+    }
+    QProcess::setProcessChannelMode(QProcess::SeparateChannels);
+}
+
+KProcess::OutputChannelMode KProcess::outputChannelMode() const
+{
+    Q_D(const KProcess);
+
+    return d->outputChannelMode;
+}
+
+void KProcess::setNextOpenMode(QIODevice::OpenMode mode)
+{
+    Q_D(KProcess);
+
+    d->openMode = mode;
+}
+
+#define DUMMYENV "_KPROCESS_DUMMY_="
+
+void KProcess::clearEnvironment()
+{
+    setEnvironment(QStringList() << QString::fromLatin1(DUMMYENV));
+}
+
+void KProcess::setEnv(const QString &name, const QString &value, bool overwrite)
+{
+    QStringList env = environment();
+    if (env.isEmpty()) {
+        env = systemEnvironment();
+        env.removeAll(QString::fromLatin1(DUMMYENV));
+    }
+    QString fname(name);
+    fname.append(QLatin1Char('='));
+    for (QStringList::Iterator it = env.begin(); it != env.end(); ++it)
+        if ((*it).startsWith(fname)) {
+            if (overwrite) {
+                *it = fname.append(value);
+                setEnvironment(env);
+            }
+            return;
+        }
+    env.append(fname.append(value));
+    setEnvironment(env);
+}
+
+void KProcess::unsetEnv(const QString &name)
+{
+    QStringList env = environment();
+    if (env.isEmpty()) {
+        env = systemEnvironment();
+        env.removeAll(QString::fromLatin1(DUMMYENV));
+    }
+    QString fname(name);
+    fname.append(QLatin1Char('='));
+    for (QStringList::Iterator it = env.begin(); it != env.end(); ++it)
+        if ((*it).startsWith(fname)) {
+            env.erase(it);
+            if (env.isEmpty())
+                env.append(QString::fromLatin1(DUMMYENV));
+            setEnvironment(env);
+            return;
+        }
+}
+
+void KProcess::setProgram(const QString &exe, const QStringList &args)
+{
+    Q_D(KProcess);
+
+    d->prog = exe;
+    d->args = args;
+#ifdef Q_OS_WIN
+    setNativeArguments(QString());
+#endif
+}
+
+void KProcess::setProgram(const QStringList &argv)
+{
+    Q_D(KProcess);
+
+    Q_ASSERT( !argv.isEmpty() );
+    d->args = argv;
+    d->prog = d->args.takeFirst();
+#ifdef Q_OS_WIN
+    setNativeArguments(QString());
+#endif
+}
+
+KProcess &KProcess::operator<<(const QString &arg)
+{
+    Q_D(KProcess);
+
+    if (d->prog.isEmpty())
+        d->prog = arg;
+    else
+        d->args << arg;
+    return *this;
+}
+
+KProcess &KProcess::operator<<(const QStringList &args)
+{
+    Q_D(KProcess);
+
+    if (d->prog.isEmpty())
+        setProgram(args);
+    else
+        d->args << args;
+    return *this;
+}
+
+void KProcess::clearProgram()
+{
+    Q_D(KProcess);
+
+    d->prog.clear();
+    d->args.clear();
+#ifdef Q_OS_WIN
+    setNativeArguments(QString());
+#endif
+}
+
+void KProcess::setShellCommand(const QString &cmd)
+{
+    Q_D(KProcess);
+    d->args.clear();
+    d->prog = QString::fromLatin1("/bin/sh");
+    d->args << QString::fromLatin1("-c") << cmd;
+}
+
+QStringList KProcess::program() const
+{
+    Q_D(const KProcess);
+
+    QStringList argv = d->args;
+    argv.prepend(d->prog);
+    return argv;
+}
+
+void KProcess::start()
+{
+    Q_D(KProcess);
+
+    QProcess::start(d->prog, d->args, d->openMode);
+}
+
+int KProcess::execute(int msecs)
+{
+    start();
+    if (!waitForFinished(msecs)) {
+        kill();
+        waitForFinished(-1);
+        return -2;
+    }
+    return (exitStatus() == QProcess::NormalExit) ? exitCode() : -1;
+}
+
+// static
+int KProcess::execute(const QString &exe, const QStringList &args, int msecs)
+{
+    KProcess p;
+    p.setProgram(exe, args);
+    return p.execute(msecs);
+}
+
+// static
+int KProcess::execute(const QStringList &argv, int msecs)
+{
+    KProcess p;
+    p.setProgram(argv);
+    return p.execute(msecs);
+}
+
+int KProcess::startDetached()
+{
+    Q_D(KProcess);
+
+    qint64 pid;
+    if (!QProcess::startDetached(d->prog, d->args, workingDirectory(), &pid))
+        return 0;
+    return (int) pid;
+}
+
+// static
+int KProcess::startDetached(const QString &exe, const QStringList &args)
+{
+    qint64 pid;
+    if (!QProcess::startDetached(exe, args, QString(), &pid))
+        return 0;
+    return (int) pid;
+}
+
+// static
+int KProcess::startDetached(const QStringList &argv)
+{
+    QStringList args = argv;
+    QString prog = args.takeFirst();
+    return startDetached(prog, args);
+}
+
+int KProcess::pid() const
+{
+#ifdef Q_OS_UNIX
+    return (int) QProcess::pid();
+#else
+    return QProcess::pid() ? QProcess::pid()->dwProcessId : 0;
+#endif
+}
+
new file mode 100644
--- /dev/null
+++ b/gui/src/kprocess.h
@@ -0,0 +1,342 @@
+/*
+    This file is part of the KDE libraries
+
+    Copyright (C) 2007 Oswald Buddenhagen <ossi@kde.org>
+
+    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 KPROCESS_H
+#define KPROCESS_H
+
+#include <QtCore/QProcess>
+class KProcess;
+class KProcessPrivate;
+
+
+/**
+ * \class KProcess kprocess.h <KProcess>
+ * 
+ * Child process invocation, monitoring and control.
+ *
+ * This class extends QProcess by some useful functionality, overrides
+ * some defaults with saner values and wraps parts of the API into a more
+ * accessible one.
+ * This is the preferred way of spawning child processes in KDE; don't
+ * use QProcess directly.
+ *
+ * @author Oswald Buddenhagen <ossi@kde.org>
+ **/
+class KProcess : public QProcess
+{
+    Q_OBJECT
+    Q_DECLARE_PRIVATE(KProcess)
+
+public:
+
+    /**
+     * Modes in which the output channels can be opened.
+     */
+    enum OutputChannelMode {
+        SeparateChannels = QProcess::SeparateChannels,
+            /**< Standard output and standard error are handled by KProcess
+                 as separate channels */
+        MergedChannels = QProcess::MergedChannels,
+            /**< Standard output and standard error are handled by KProcess
+                 as one channel */
+        ForwardedChannels = QProcess::ForwardedChannels,
+            /**< Both standard output and standard error are forwarded
+                 to the parent process' respective channel */
+        OnlyStdoutChannel,
+            /**< Only standard output is handled; standard error is forwarded */
+        OnlyStderrChannel  /**< Only standard error is handled; standard output is forwarded */
+    };
+
+    /**
+     * Constructor
+     */
+    explicit KProcess(QObject *parent = 0);
+
+    /**
+     * Destructor
+     */
+    virtual ~KProcess();
+
+    /**
+     * Set how to handle the output channels of the child process.
+     *
+     * The default is ForwardedChannels, which is unlike in QProcess.
+     * Do not request more than you actually handle, as this output is
+     * simply lost otherwise.
+     *
+     * This function must be called before starting the process.
+     *
+     * @param mode the output channel handling mode
+     */
+    void setOutputChannelMode(OutputChannelMode mode);
+
+    /**
+     * Query how the output channels of the child process are handled.
+     *
+     * @return the output channel handling mode
+     */
+    OutputChannelMode outputChannelMode() const;
+
+    /**
+     * Set the QIODevice open mode the process will be opened in.
+     *
+     * This function must be called before starting the process, obviously.
+     *
+     * @param mode the open mode. Note that this mode is automatically
+     *   "reduced" according to the channel modes and redirections.
+     *   The default is QIODevice::ReadWrite.
+     */
+    void setNextOpenMode(QIODevice::OpenMode mode);
+
+    /**
+     * 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
+     * @param overwrite if @c false and the environment variable is already
+     *   set, the old value will be preserved
+     */
+    void setEnv(const QString &name, const QString &value, bool overwrite = true);
+
+    /**
+     * Removes the variable @p name from the process' environment.
+     *
+     * This function must be called before starting the process.
+     *
+     * @param name the name of the environment variable
+     */
+    void unsetEnv(const QString &name);
+
+    /**
+     * Empties the process' environment.
+     *
+     * Note that LD_LIBRARY_PATH/DYLD_LIBRARY_PATH is automatically added
+     * on *NIX.
+     *
+     * This function must be called before starting the process.
+     */
+    void clearEnvironment();
+
+    /**
+     * Set the program and the command line arguments.
+     *
+     * This function must be called before starting the process, obviously.
+     *
+     * @param exe the program to execute
+     * @param args the command line arguments for the program,
+     *   one per list element
+     */
+    void setProgram(const QString &exe, const QStringList &args = QStringList());
+
+    /**
+     * @overload
+     *
+     * @param argv the program to execute and the command line arguments
+     *   for the program, one per list element
+     */
+    void setProgram(const QStringList &argv);
+
+    /**
+     * Append an element to the command line argument list for this process.
+     *
+     * If no executable is set yet, it will be set instead.
+     *
+     * For example, doing an "ls -l /usr/local/bin" can be achieved by:
+     *  \code
+     *  KProcess p;
+     *  p << "ls" << "-l" << "/usr/local/bin";
+     *  ...
+     *  \endcode
+     *
+     * This function must be called before starting the process, obviously.
+     *
+     * @param arg the argument to add
+     * @return a reference to this KProcess
+     */
+    KProcess &operator<<(const QString& arg);
+
+    /**
+     * @overload
+     *
+     * @param args the arguments to add
+     * @return a reference to this KProcess
+     */
+    KProcess &operator<<(const QStringList& args);
+
+    /**
+     * Clear the program and command line argument list.
+     */
+    void clearProgram();
+
+    /**
+     * Set a command to execute through a shell (a POSIX sh on *NIX
+     * and cmd.exe on Windows).
+     *
+     * Using this for anything but user-supplied commands is usually a bad
+     * idea, as the command's syntax depends on the platform.
+     * Redirections including pipes, etc. are better handled by the
+     * respective functions provided by QProcess.
+     *
+     * If KProcess determines that the command does not really need a
+     * shell, it will trasparently execute it without one for performance
+     * reasons.
+     *
+     * This function must be called before starting the process, obviously.
+     *
+     * @param cmd the command to execute through a shell.
+     *   The caller must make sure that all filenames etc. are properly
+     *   quoted when passed as argument. Failure to do so often results in
+     *   serious security holes. See KShell::quoteArg().
+     */
+    void setShellCommand(const QString &cmd);
+
+    /**
+     * Obtain the currently set program and arguments.
+     *
+     * @return a list, the first element being the program, the remaining ones
+     *  being command line arguments to the program.
+     */
+    QStringList program() const;
+
+    /**
+     * Start the process.
+     *
+     * @see QProcess::start(const QString &, const QStringList &, OpenMode)
+     */
+    void start();
+
+    /**
+     * Start the process, wait for it to finish, and return the exit code.
+     *
+     * This method is roughly equivalent to the sequence:
+     * <code>
+     *   start();
+     *   waitForFinished(msecs);
+     *   return exitCode();
+     * </code>
+     *
+     * Unlike the other execute() variants this method is not static,
+     * so the process can be parametrized properly and talked to.
+     *
+     * @param msecs time to wait for process to exit before killing it
+     * @return -2 if the process could not be started, -1 if it crashed,
+     *  otherwise its exit code
+     */
+    int execute(int msecs = -1);
+
+    /**
+     * @overload
+     *
+     * @param exe the program to execute
+     * @param args the command line arguments for the program,
+     *   one per list element
+     * @param msecs time to wait for process to exit before killing it
+     * @return -2 if the process could not be started, -1 if it crashed,
+     *  otherwise its exit code
+     */
+    static int execute(const QString &exe, const QStringList &args = QStringList(), int msecs = -1);
+
+    /**
+     * @overload
+     *
+     * @param argv the program to execute and the command line arguments
+     *   for the program, one per list element
+     * @param msecs time to wait for process to exit before killing it
+     * @return -2 if the process could not be started, -1 if it crashed,
+     *  otherwise its exit code
+     */
+    static int execute(const QStringList &argv, int msecs = -1);
+
+    /**
+     * Start the process and detach from it. See QProcess::startDetached()
+     * for details.
+     *
+     * Unlike the other startDetached() variants this method is not static,
+     * so the process can be parametrized properly.
+     * @note Currently, only the setProgram()/setShellCommand() and
+     * setWorkingDirectory() parametrizations are supported.
+     *
+     * The KProcess object may be re-used immediately after calling this
+     * function.
+     *
+     * @return the PID of the started process or 0 on error
+     */
+    int startDetached();
+
+    /**
+     * @overload
+     *
+     * @param exe the program to start
+     * @param args the command line arguments for the program,
+     *   one per list element
+     * @return the PID of the started process or 0 on error
+     */
+    static int startDetached(const QString &exe, const QStringList &args = QStringList());
+
+    /**
+     * @overload
+     *
+     * @param argv the program to start and the command line arguments
+     *   for the program, one per list element
+     * @return the PID of the started process or 0 on error
+     */
+    static int startDetached(const QStringList &argv);
+
+    /**
+     * Obtain the process' ID as known to the system.
+     *
+     * Unlike with QProcess::pid(), this is a real PID also on Windows.
+     *
+     * This function can be called only while the process is running.
+     * It cannot be applied to detached processes.
+     *
+     * @return the process ID
+     */
+    int pid() const;
+
+protected:
+    /**
+     * @internal
+     */
+    KProcess(KProcessPrivate *d, QObject *parent);
+
+    /**
+     * @internal
+     */
+    KProcessPrivate * const d_ptr;
+
+private:
+    // hide those
+    using QProcess::setReadChannelMode;
+    using QProcess::readChannelMode;
+    using QProcess::setProcessChannelMode;
+    using QProcess::processChannelMode;
+
+    Q_PRIVATE_SLOT(d_func(), void _k_forwardStdout())
+    Q_PRIVATE_SLOT(d_func(), void _k_forwardStderr())
+};
+
+#include "kprocess_p.h"
+
+#endif
+
new file mode 100644
--- /dev/null
+++ b/gui/src/kprocess_p.h
@@ -0,0 +1,49 @@
+/*
+    This file is part of the KDE libraries
+
+    Copyright (C) 2007 Oswald Buddenhagen <ossi@kde.org>
+
+    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 KPROCESS_P_H
+#define KPROCESS_P_H
+class KProcess;
+class KProcessPrivate;
+
+#include "kprocess.h"
+class KProcessPrivate {
+    Q_DECLARE_PUBLIC(KProcess)
+protected:
+    KProcessPrivate() :
+        openMode(QIODevice::ReadWrite)
+    {
+    }
+    void writeAll(const QByteArray &buf, int fd);
+    void forwardStd(KProcess::ProcessChannel good, int fd);
+    void _k_forwardStdout();
+    void _k_forwardStderr();
+
+    QString prog;
+    QStringList args;
+    KProcess::OutputChannelMode outputChannelMode;
+    QIODevice::OpenMode openMode;
+
+    KProcess *q_ptr;
+};
+
+
+#endif
new file mode 100644
--- /dev/null
+++ b/gui/src/kpty.cpp
@@ -0,0 +1,710 @@
+/*
+
+   This file is part of the KDE libraries
+   Copyright (C) 2002 Waldo Bastian <bastian@kde.org>
+   Copyright (C) 2002-2003,2007-2008 Oswald Buddenhagen <ossi@kde.org>
+   Copyright (C) 2010 KDE e.V. <kde-ev-board@kde.org>
+     Author Adriaan de Groot <groot@kde.org>
+
+   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
+
+#define HAVE_UTMPX
+#define _UTMPX_COMPAT
+
+#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__) || defined(__sun)
+#  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__) || defined(__sun)
+#  define _tcsetattr(fd, ttmode) tcsetattr(fd, TCSANOW, ttmode)
+# else
+#  define _tcsetattr(fd, ttmode) ioctl(fd, TCSETS, (char *)ttmode)
+# endif
+#endif
+
+#include <QtCore/Q_PID>
+
+#define TTY_GROUP "tty"
+
+#ifndef PATH_MAX
+# ifdef MAXPATHLEN
+#  define PATH_MAX MAXPATHLEN
+# else
+#  define PATH_MAX 1024
+# endif
+#endif
+
+///////////////////////
+// private functions //
+///////////////////////
+
+//////////////////
+// private data //
+//////////////////
+
+KPtyPrivate::KPtyPrivate(KPty* parent) :
+    masterFd(-1), slaveFd(-1), ownMaster(true), q_ptr(parent)
+{
+}
+
+KPtyPrivate::~KPtyPrivate()
+{
+}
+
+#ifndef HAVE_OPENPTY
+bool KPtyPrivate::chownpty(bool grant)
+{
+    return !QProcess::execute(KStandardDirs::findExe("kgrantpty"),
+        QStringList() << (grant?"--grant":"--revoke") << QString::number(masterFd));
+}
+#endif
+
+/////////////////////////////
+// public member functions //
+/////////////////////////////
+
+KPty::KPty() :
+    d_ptr(new KPtyPrivate(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;
+
+  d->ownMaster = 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 = KDE_open(PTM_DEVICE, O_RDWR|O_NOCTTY);
+d->masterFd = ::open(PTM_DEVICE, O_RDWR|O_NOCTTY);
+#else
+# error No method to open a PTY master detected.
+#endif
+  if (d->masterFd >= 0)
+  {
+#ifdef HAVE_PTSNAME
+    char *ptsn = ptsname(d->masterFd);
+    if (ptsn) {
+        d->ttyName = ptsn;
+#else
+    int ptyno;
+    if (!ioctl(d->masterFd, TIOCGPTN, &ptyno)) {
+        char buf[32];
+        sprintf(buf, "/dev/pts/%d", ptyno);
+        d->ttyName = buf;
+#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;
+      }
+    }
+  }
+
+  //kWarning(175) << "Can't open a pseudo teletype";
+  return false;
+
+ gotpty:
+  KDE_struct_stat st;
+  if (KDE_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))
+  {
+
+    /*kWarning(175)
+      << "chownpty failed for device " << ptyName << "::" << d->ttyName
+      << "\nThis means the communication can be eavesdropped." << endl;
+*/  
+}
+
+ grantedpt:
+
+#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)
+  {
+    //kWarning(175) << "Can't open slave pseudo teletype";
+    ::close(d->masterFd);
+    d->masterFd = -1;
+    return false;
+  }
+
+#if (defined(__svr4__) || defined(__sgi__) || defined(Q_OS_SOLARIS))
+  // Solaris uses STREAMS for terminal handling. It is possible
+  // for the pty handling modules to be left off the stream; in that
+  // case push them on. ioctl(fd, I_FIND, ...) is documented to return
+  // 1 if the module is on the stream already.
+  {
+    static const char *pt = "ptem";
+    static const char *ld = "ldterm";
+    if (ioctl(d->slaveFd, I_FIND, pt) == 0)
+      ioctl(d->slaveFd, I_PUSH, pt);
+    if (ioctl(d->slaveFd, I_FIND, ld) == 0)
+      ioctl(d->slaveFd, I_PUSH, ld);
+  }
+#endif
+
+#endif /* HAVE_OPENPTY */
+
+  fcntl(d->masterFd, F_SETFD, FD_CLOEXEC);
+  fcntl(d->slaveFd, F_SETFD, FD_CLOEXEC);
+
+  return true;
+}
+
+bool KPty::open(int fd)
+{
+#if !defined(HAVE_PTSNAME) && !defined(TIOCGPTN)
+    //kWarning(175) << "Unsupported attempt to open pty with fd" << fd;
+    return false;
+#else
+    Q_D(KPty);
+
+    if (d->masterFd >= 0) {
+        //kWarning(175) << "Attempting to open an already open pty";
+        return false;
+    }
+
+    d->ownMaster = false;
+
+# ifdef HAVE_PTSNAME
+    char *ptsn = ptsname(fd);
+    if (ptsn) {
+        d->ttyName = ptsn;
+# else
+    int ptyno;
+    if (!ioctl(fd, TIOCGPTN, &ptyno)) {
+        char buf[32];
+        sprintf(buf, "/dev/pts/%d", ptyno);
+        d->ttyName = buf;
+# endif
+    } else {
+        //kWarning(175) << "Failed to determine pty slave device for fd" << fd;
+        return false;
+    }
+
+    d->masterFd = fd;
+    if (!openSlave()) {
+        d->masterFd = -1;
+        return false;
+    }
+
+    return true;
+#endif
+}
+
+void KPty::closeSlave()
+{
+    Q_D(KPty);
+
+    if (d->slaveFd < 0)
+        return;
+    ::close(d->slaveFd);
+    d->slaveFd = -1;
+}
+
+bool KPty::openSlave()
+{
+    Q_D(KPty);
+
+    if (d->slaveFd >= 0)
+        return true;
+    if (d->masterFd < 0) {
+        //kWarning(175) << "Attempting to open pty slave while master is closed";
+        return false;
+    }
+    d->slaveFd = ::open(d->ttyName.data(), O_RDWR | O_NOCTTY);
+    if (d->slaveFd < 0) {
+        //kWarning(175) << "Can't open slave pseudo teletype";
+        return false;
+    }
+    fcntl(d->slaveFd, F_SETFD, FD_CLOEXEC);
+    return true;
+}
+
+void KPty::close()
+{
+    Q_D(KPty);
+
+    if (d->masterFd < 0)
+        return;
+    closeSlave();
+    if (d->ownMaster) {
+#ifndef HAVE_OPENPTY
+        // 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);
+            }
+        }
+#endif
+        ::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);
+    gettimeofday((struct timeval *)&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);
+	gettimeofday((struct timeval *)&(ut->ut_tv), 0);
+        pututxline(ut);
+    }
+    endutxent();
+#  else
+        ut->ut_time = time(0);
+        pututline(ut);
+    }
+    endutent();
+#  endif
+# endif
+#endif
+}
+
+bool KPty::tcGetAttr(struct ::termios *ttmode) const
+{
+    Q_D(const KPty);
+
+#ifdef Q_OS_SOLARIS
+    if (_tcgetattr(d->slaveFd, ttmode) == 0) return true;
+#endif
+    return _tcgetattr(d->masterFd, ttmode) == 0;
+}
+
+bool KPty::tcSetAttr(struct ::termios *ttmode)
+{
+    Q_D(KPty);
+
+#ifdef Q_OS_SOLARIS
+    if (_tcsetattr(d->slaveFd, ttmode) == 0) return true;
+#endif
+    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/src/kpty.h
@@ -0,0 +1,204 @@
+/* This file is part of the KDE libraries
+
+    Copyright (C) 2003,2007 Oswald Buddenhagen <ossi@kde.org>
+
+    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/qglobal.h>
+
+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();
+
+  /**
+   * Open using an existing pty master.
+   *
+   * @param fd an open pty master file descriptor.
+   *   The ownership of the fd remains with the caller;
+   *   it will not be automatically closed at any point.
+   * @return true if a pty pair was successfully opened
+   */
+  bool open(int fd);
+
+  /**
+   * 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();
+
+  /**
+   * Open the pty slave descriptor.
+   *
+   * This undoes the effect of closeSlave().
+   *
+   * @return true if the pty slave was successfully opened
+   */
+  bool openSlave();
+
+  /**
+   * 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/src/kpty_export.h
@@ -0,0 +1,46 @@
+/*  This file is part of the KDE project
+    Copyright (C) 2007 David Faure <faure@kde.org>
+
+    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_EXPORT_H
+#define KPTY_EXPORT_H
+
+/* needed for KDE_EXPORT and KDE_IMPORT macros */
+//#include <kdemacros.h>
+#include <QtCore/qglobal.h>
+#define KDE_EXPORT
+#define KDE_IMPORT
+
+#ifndef KPTY_EXPORT
+# if defined(KDELIBS_STATIC_LIBS)
+   /* No export/import for static libraries */
+#  define KPTY_EXPORT
+# elif defined(MAKE_KDECORE_LIB)
+   /* We are building this library */ 
+#  define KPTY_EXPORT KDE_EXPORT
+# else
+   /* We are using this library */ 
+#  define KPTY_EXPORT KDE_IMPORT
+# endif
+#endif
+
+# ifndef KPTY_EXPORT_DEPRECATED
+#  define KPTY_EXPORT_DEPRECATED KDE_DEPRECATED KPTY_EXPORT
+# endif
+
+#endif
new file mode 100644
--- /dev/null
+++ b/gui/src/kpty_p.h
@@ -0,0 +1,58 @@
+/* This file is part of the KDE libraries
+
+    Copyright (C) 2003,2007 Oswald Buddenhagen <ossi@kde.org>
+
+    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"
+
+#if defined(Q_OS_MAC)
+#define HAVE_UTIL_H
+#define HAVE_UTMPX
+#define _UTMPX_COMPAT
+#define HAVE_PTSNAME
+#define HAVE_SYS_TIME_H
+#else
+#define HAVE_PTY_H
+#endif
+
+#define HAVE_OPENPTY
+
+#include <QtCore/QByteArray>
+
+struct KPtyPrivate {
+    Q_DECLARE_PUBLIC(KPty)
+
+    KPtyPrivate(KPty* parent);
+    virtual ~KPtyPrivate();
+#ifndef HAVE_OPENPTY
+    bool chownpty(bool grant);
+#endif
+
+    int masterFd;
+    int slaveFd;
+    bool ownMaster:1;
+
+    QByteArray ttyName;
+
+    KPty *q_ptr;
+};
+
+#endif
new file mode 100644
--- /dev/null
+++ b/gui/src/kptydevice.cpp
@@ -0,0 +1,413 @@
+/*
+
+   This file is part of the KDE libraries
+   Copyright (C) 2007 Oswald Buddenhagen <ossi@kde.org>
+   Copyright (C) 2010 KDE e.V. <kde-ev-board@kde.org>
+     Author Adriaan de Groot <groot@kde.org>
+
+   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 "kptydevice.h"
+#include "kpty_p.h"
+#define i18n
+
+#include <QtCore/QSocketNotifier>
+
+#include <unistd.h>
+#include <errno.h>
+#include <signal.h>
+#include <termios.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#ifdef HAVE_SYS_FILIO_H
+# include <sys/filio.h>
+#endif
+#ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+#endif
+
+#if defined(Q_OS_FREEBSD) || defined(Q_OS_MAC)
+  // "the other end's output queue size" - kinda braindead, huh?
+# define PTY_BYTES_AVAILABLE TIOCOUTQ
+#elif defined(TIOCINQ)
+  // "our end's input queue size"
+# define PTY_BYTES_AVAILABLE TIOCINQ
+#else
+  // likewise. more generic ioctl (theoretically)
+# define PTY_BYTES_AVAILABLE FIONREAD
+#endif
+
+//////////////////
+// private data //
+//////////////////
+
+// Lifted from Qt. I don't think they would mind. ;)
+// Re-lift again from Qt whenever a proper replacement for pthread_once appears
+static void qt_ignore_sigpipe()
+{
+    static QBasicAtomicInt atom = Q_BASIC_ATOMIC_INITIALIZER(0);
+    if (atom.testAndSetRelaxed(0, 1)) {
+        struct sigaction noaction;
+        memset(&noaction, 0, sizeof(noaction));
+        noaction.sa_handler = SIG_IGN;
+        sigaction(SIGPIPE, &noaction, 0);
+    }
+}
+
+#define NO_INTR(ret,func) do { ret = func; } while (ret < 0 && errno == EINTR)
+
+bool KPtyDevicePrivate::_k_canRead()
+{
+    Q_Q(KPtyDevice);
+    qint64 readBytes = 0;
+
+#ifdef Q_OS_IRIX // this should use a config define, but how to check it?
+    size_t available;
+#else
+    int available;
+#endif
+    if (!::ioctl(q->masterFd(), PTY_BYTES_AVAILABLE, (char *) &available)) {
+#ifdef Q_OS_SOLARIS
+        // A Pty is a STREAMS module, and those can be activated
+        // with 0 bytes available. This happens either when ^C is
+        // pressed, or when an application does an explicit write(a,b,0)
+        // which happens in experiments fairly often. When 0 bytes are
+        // available, you must read those 0 bytes to clear the STREAMS
+        // module, but we don't want to hit the !readBytes case further down.
+        if (!available) {
+            char c;
+            // Read the 0-byte STREAMS message
+            NO_INTR(readBytes, read(q->masterFd(), &c, 0));
+            // Should return 0 bytes read; -1 is error
+            if (readBytes < 0) {
+                readNotifier->setEnabled(false);
+                emit q->readEof();
+                return false;
+            }
+            return true;
+        }
+#endif
+
+        char *ptr = readBuffer.reserve(available);
+#ifdef Q_OS_SOLARIS
+        // Even if available > 0, it is possible for read()
+        // to return 0 on Solaris, due to 0-byte writes in the stream.
+        // Ignore them and keep reading until we hit *some* data.
+        // In Solaris it is possible to have 15 bytes available
+        // and to (say) get 0, 0, 6, 0 and 9 bytes in subsequent reads.
+        // Because the stream is set to O_NONBLOCK in finishOpen(),
+        // an EOF read will return -1.
+        readBytes = 0;
+        while (!readBytes)
+#endif
+        // Useless block braces except in Solaris
+        {
+          NO_INTR(readBytes, read(q->masterFd(), ptr, available));
+        }
+        if (readBytes < 0) {
+            readBuffer.unreserve(available);
+            q->setErrorString(i18n("Error reading from PTY"));
+            return false;
+        }
+        readBuffer.unreserve(available - readBytes); // *should* be a no-op
+    }
+
+    if (!readBytes) {
+        readNotifier->setEnabled(false);
+        emit q->readEof();
+        return false;
+    } else {
+        if (!emittedReadyRead) {
+            emittedReadyRead = true;
+            emit q->readyRead();
+            emittedReadyRead = false;
+        }
+        return true;
+    }
+}
+
+bool KPtyDevicePrivate::_k_canWrite()
+{
+    Q_Q(KPtyDevice);
+
+    writeNotifier->setEnabled(false);
+    if (writeBuffer.isEmpty())
+        return false;
+
+    qt_ignore_sigpipe();
+    int wroteBytes;
+    NO_INTR(wroteBytes,
+            write(q->masterFd(),
+                  writeBuffer.readPointer(), writeBuffer.readSize()));
+    if (wroteBytes < 0) {
+        q->setErrorString(i18n("Error writing to PTY"));
+        return false;
+    }
+    writeBuffer.free(wroteBytes);
+
+    if (!emittedBytesWritten) {
+        emittedBytesWritten = true;
+        emit q->bytesWritten(wroteBytes);
+        emittedBytesWritten = false;
+    }
+
+    if (!writeBuffer.isEmpty())
+        writeNotifier->setEnabled(true);
+    return true;
+}
+
+#ifndef timeradd
+// Lifted from GLIBC
+# define timeradd(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 >= 1000000) { \
+            ++(result)->tv_sec; \
+            (result)->tv_usec -= 1000000; \
+        } \
+    } while (0)
+# 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 KPtyDevicePrivate::doWait(int msecs, bool reading)
+{
+    Q_Q(KPtyDevice);
+#ifndef __linux__
+    struct timeval etv;
+#endif
+    struct timeval tv, *tvp;
+
+    if (msecs < 0)
+        tvp = 0;
+    else {
+        tv.tv_sec = msecs / 1000;
+        tv.tv_usec = (msecs % 1000) * 1000;
+#ifndef __linux__
+        gettimeofday(&etv, 0);
+        timeradd(&tv, &etv, &etv);
+#endif
+        tvp = &tv;
+    }
+
+    while (reading ? readNotifier->isEnabled() : !writeBuffer.isEmpty()) {
+        fd_set rfds;
+        fd_set wfds;
+
+        FD_ZERO(&rfds);
+        FD_ZERO(&wfds);
+
+        if (readNotifier->isEnabled())
+            FD_SET(q->masterFd(), &rfds);
+        if (!writeBuffer.isEmpty())
+            FD_SET(q->masterFd(), &wfds);
+
+#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(q->masterFd() + 1, &rfds, &wfds, 0, tvp)) {
+        case -1:
+            if (errno == EINTR)
+                break;
+            return false;
+        case 0:
+            q->setErrorString(i18n("PTY operation timed out"));
+            return false;
+        default:
+            if (FD_ISSET(q->masterFd(), &rfds)) {
+                bool canRead = _k_canRead();
+                if (reading && canRead)
+                    return true;
+            }
+            if (FD_ISSET(q->masterFd(), &wfds)) {
+                bool canWrite = _k_canWrite();
+                if (!reading)
+                    return canWrite;
+            }
+            break;
+        }
+    }
+    return false;
+}
+
+void KPtyDevicePrivate::finishOpen(QIODevice::OpenMode mode)
+{
+    Q_Q(KPtyDevice);
+
+    q->QIODevice::open(mode);
+    fcntl(q->masterFd(), F_SETFL, O_NONBLOCK);
+    readBuffer.clear();
+    readNotifier = new QSocketNotifier(q->masterFd(), QSocketNotifier::Read, q);
+    writeNotifier = new QSocketNotifier(q->masterFd(), QSocketNotifier::Write, q);
+    QObject::connect(readNotifier, SIGNAL(activated(int)), q, SLOT(_k_canRead()));
+    QObject::connect(writeNotifier, SIGNAL(activated(int)), q, SLOT(_k_canWrite()));
+    readNotifier->setEnabled(true);
+}
+
+/////////////////////////////
+// public member functions //
+/////////////////////////////
+
+KPtyDevice::KPtyDevice(QObject *parent) :
+    QIODevice(parent),
+    KPty(new KPtyDevicePrivate(this))
+{
+}
+
+KPtyDevice::~KPtyDevice()
+{
+    close();
+}
+
+bool KPtyDevice::open(OpenMode mode)
+{
+    Q_D(KPtyDevice);
+
+    if (masterFd() >= 0)
+        return true;
+
+    if (!KPty::open()) {
+        setErrorString(i18n("Error opening PTY"));
+        return false;
+    }
+
+    d->finishOpen(mode);
+
+    return true;
+}
+
+bool KPtyDevice::open(int fd, OpenMode mode)
+{
+    Q_D(KPtyDevice);
+
+    if (!KPty::open(fd)) {
+        setErrorString(i18n("Error opening PTY"));
+        return false;
+    }
+
+    d->finishOpen(mode);
+
+    return true;
+}
+
+void KPtyDevice::close()
+{
+    Q_D(KPtyDevice);
+
+    if (masterFd() < 0)
+        return;
+
+    delete d->readNotifier;
+    delete d->writeNotifier;
+
+    QIODevice::close();
+
+    KPty::close();
+}
+
+bool KPtyDevice::isSequential() const
+{
+    return true;
+}
+
+bool KPtyDevice::canReadLine() const
+{
+    Q_D(const KPtyDevice);
+    return QIODevice::canReadLine() || d->readBuffer.canReadLine();
+}
+
+bool KPtyDevice::atEnd() const
+{
+    Q_D(const KPtyDevice);
+    return QIODevice::atEnd() && d->readBuffer.isEmpty();
+}
+
+qint64 KPtyDevice::bytesAvailable() const
+{
+    Q_D(const KPtyDevice);
+    return QIODevice::bytesAvailable() + d->readBuffer.size();
+}
+
+qint64 KPtyDevice::bytesToWrite() const
+{
+    Q_D(const KPtyDevice);
+    return d->writeBuffer.size();
+}
+
+bool KPtyDevice::waitForReadyRead(int msecs)
+{
+    Q_D(KPtyDevice);
+    return d->doWait(msecs, true);
+}
+
+bool KPtyDevice::waitForBytesWritten(int msecs)
+{
+    Q_D(KPtyDevice);
+    return d->doWait(msecs, false);
+}
+
+void KPtyDevice::setSuspended(bool suspended)
+{
+    Q_D(KPtyDevice);
+    d->readNotifier->setEnabled(!suspended);
+}
+
+bool KPtyDevice::isSuspended() const
+{
+    Q_D(const KPtyDevice);
+    return !d->readNotifier->isEnabled();
+}
+
+// protected
+qint64 KPtyDevice::readData(char *data, qint64 maxlen)
+{
+    Q_D(KPtyDevice);
+    return d->readBuffer.read(data, (int)qMin<qint64>(maxlen, KMAXINT));
+}
+
+// protected
+qint64 KPtyDevice::readLineData(char *data, qint64 maxlen)
+{
+    Q_D(KPtyDevice);
+    return d->readBuffer.readLine(data, (int)qMin<qint64>(maxlen, KMAXINT));
+}
+
+// protected
+qint64 KPtyDevice::writeData(const char *data, qint64 len)
+{
+    Q_D(KPtyDevice);
+    Q_ASSERT(len <= KMAXINT);
+
+    d->writeBuffer.write(data, len);
+    d->writeNotifier->setEnabled(true);
+    return len;
+}
+
new file mode 100644
--- /dev/null
+++ b/gui/src/kptydevice.h
@@ -0,0 +1,353 @@
+/* This file is part of the KDE libraries
+
+    Copyright (C) 2007 Oswald Buddenhagen <ossi@kde.org>
+
+    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 kptydev_h
+#define kptydev_h
+
+struct KPtyPrivate;
+struct KPtyDevicePrivate;
+
+#include "kpty.h"
+#include "kpty_p.h"
+#include <QtCore/QIODevice>
+#include <QSocketNotifier>
+
+#define Q_DECLARE_PRIVATE_MI(Class, SuperClass) \
+    inline Class##Private* d_func() { return reinterpret_cast<Class##Private *>(SuperClass::d_ptr); } \
+    inline const Class##Private* d_func() const { return reinterpret_cast<const Class##Private *>(SuperClass::d_ptr); } \
+    friend class Class##Private;
+
+/**
+ * Encapsulates KPty into a QIODevice, so it can be used with Q*Stream, etc.
+ */
+class KPtyDevice : public QIODevice, public KPty { //krazy:exclude=dpointer (via macro)
+    Q_OBJECT
+    Q_DECLARE_PRIVATE_MI(KPtyDevice, KPty)
+
+public:
+
+    /**
+     * Constructor
+     */
+    KPtyDevice(QObject *parent = 0);
+
+    /**
+     * Destructor:
+     *
+     *  If the pty is still open, it will be closed. Note, however, that
+     *  an utmp registration is @em not undone.
+     */
+    virtual ~KPtyDevice();
+
+    /**
+     * Create a pty master/slave pair.
+     *
+     * @return true if a pty pair was successfully opened
+     */
+    virtual bool open(OpenMode mode = ReadWrite | Unbuffered);
+
+    /**
+     * Open using an existing pty master. The ownership of the fd
+     * remains with the caller, i.e., close() will not close the fd.
+     *
+     * This is useful if you wish to attach a secondary "controller" to an
+     * existing pty device such as a terminal widget.
+     * Note that you will need to use setSuspended() on both devices to
+     * control which one gets the incoming data from the pty.
+     *
+     * @param fd an open pty master file descriptor.
+     * @param mode the device mode to open the pty with.
+     * @return true if a pty pair was successfully opened
+     */
+    bool open(int fd, OpenMode mode = ReadWrite | Unbuffered);
+
+    /**
+     * Close the pty master/slave pair.
+     */
+    virtual void close();
+
+    /**
+     * Sets whether the KPtyDevice monitors the pty for incoming data.
+     *
+     * When the KPtyDevice is suspended, it will no longer attempt to buffer
+     * data that becomes available from the pty and it will not emit any
+     * signals.
+     *
+     * Do not use on closed ptys.
+     * After a call to open(), the pty is not suspended. If you need to
+     * ensure that no data is read, call this function before the main loop
+     * is entered again (i.e., immediately after opening the pty).
+     */
+    void setSuspended(bool suspended);
+
+    /**
+     * Returns true if the KPtyDevice is not monitoring the pty for incoming
+     * data.
+     *
+     * Do not use on closed ptys.
+     *
+     * See setSuspended()
+     */
+    bool isSuspended() const;
+
+    /**
+     * @return always true
+     */
+    virtual bool isSequential() const;
+
+    /**
+     * @reimp
+     */
+    bool canReadLine() const;
+
+    /**
+     * @reimp
+     */
+    bool atEnd() const;
+
+    /**
+     * @reimp
+     */
+    qint64 bytesAvailable() const;
+
+    /**
+     * @reimp
+     */
+    qint64 bytesToWrite() const;
+
+    bool waitForBytesWritten(int msecs = -1);
+    bool waitForReadyRead(int msecs = -1);
+
+
+Q_SIGNALS:
+    /**
+     * Emitted when EOF is read from the PTY.
+     *
+     * Data may still remain in the buffers.
+     */
+    void readEof();
+
+protected:
+    virtual qint64 readData(char *data, qint64 maxSize);
+    virtual qint64 readLineData(char *data, qint64 maxSize);
+    virtual qint64 writeData(const char *data, qint64 maxSize);
+
+private:
+    Q_PRIVATE_SLOT(d_func(), bool _k_canRead())
+    Q_PRIVATE_SLOT(d_func(), bool _k_canWrite())
+};
+
+#define KMAXINT ((int)(~0U >> 1))
+
+/////////////////////////////////////////////////////
+// Helper. Remove when QRingBuffer becomes public. //
+/////////////////////////////////////////////////////
+
+#include <QtCore/qbytearray.h>
+#include <QtCore/qlinkedlist.h>
+
+#define CHUNKSIZE 4096
+
+class KRingBuffer
+{
+public:
+    KRingBuffer()
+    {
+        clear();
+    }
+
+    void clear()
+    {
+        buffers.clear();
+        QByteArray tmp;
+        tmp.resize(CHUNKSIZE);
+        buffers << tmp;
+        head = tail = 0;
+        totalSize = 0;
+    }
+
+    inline bool isEmpty() const
+    {
+        return buffers.count() == 1 && !tail;
+    }
+
+    inline int size() const
+    {
+        return totalSize;
+    }
+
+    inline int readSize() const
+    {
+        return (buffers.count() == 1 ? tail : buffers.first().size()) - head;
+    }
+
+    inline const char *readPointer() const
+    {
+        Q_ASSERT(totalSize > 0);
+        return buffers.first().constData() + head;
+    }
+
+    void free(int bytes)
+    {
+        totalSize -= bytes;
+        Q_ASSERT(totalSize >= 0);
+
+        forever {
+            int nbs = readSize();
+
+            if (bytes < nbs) {
+                head += bytes;
+                if (head == tail && buffers.count() == 1) {
+                    buffers.first().resize(CHUNKSIZE);
+                    head = tail = 0;
+                }
+                break;
+            }
+
+            bytes -= nbs;
+            if (buffers.count() == 1) {
+                buffers.first().resize(CHUNKSIZE);
+                head = tail = 0;
+                break;
+            }
+
+            buffers.removeFirst();
+            head = 0;
+        }
+    }
+
+    char *reserve(int bytes)
+    {
+        totalSize += bytes;
+
+        char *ptr;
+        if (tail + bytes <= buffers.last().size()) {
+            ptr = buffers.last().data() + tail;
+            tail += bytes;
+        } else {
+            buffers.last().resize(tail);
+            QByteArray tmp;
+            tmp.resize(qMax(CHUNKSIZE, bytes));
+            ptr = tmp.data();
+            buffers << tmp;
+            tail = bytes;
+        }
+        return ptr;
+    }
+
+    // release a trailing part of the last reservation
+    inline void unreserve(int bytes)
+    {
+        totalSize -= bytes;
+        tail -= bytes;
+    }
+
+    inline void write(const char *data, int len)
+    {
+        memcpy(reserve(len), data, len);
+    }
+
+    // Find the first occurrence of c and return the index after it.
+    // If c is not found until maxLength, maxLength is returned, provided
+    // it is smaller than the buffer size. Otherwise -1 is returned.
+    int indexAfter(char c, int maxLength = KMAXINT) const
+    {
+        int index = 0;
+        int start = head;
+        QLinkedList<QByteArray>::ConstIterator it = buffers.begin();
+        forever {
+            if (!maxLength)
+                return index;
+            if (index == size())
+                return -1;
+            const QByteArray &buf = *it;
+            ++it;
+            int len = qMin((it == buffers.end() ? tail : buf.size()) - start,
+                           maxLength);
+            const char *ptr = buf.data() + start;
+            if (const char *rptr = (const char *)memchr(ptr, c, len))
+                return index + (rptr - ptr) + 1;
+            index += len;
+            maxLength -= len;
+            start = 0;
+        }
+    }
+
+    inline int lineSize(int maxLength = KMAXINT) const
+    {
+        return indexAfter('\n', maxLength);
+    }
+
+    inline bool canReadLine() const
+    {
+        return lineSize() != -1;
+    }
+
+    int read(char *data, int maxLength)
+    {
+        int bytesToRead = qMin(size(), maxLength);
+        int readSoFar = 0;
+        while (readSoFar < bytesToRead) {
+            const char *ptr = readPointer();
+            int bs = qMin(bytesToRead - readSoFar, readSize());
+            memcpy(data + readSoFar, ptr, bs);
+            readSoFar += bs;
+            free(bs);
+        }
+        return readSoFar;
+    }
+
+    int readLine(char *data, int maxLength)
+    {
+        return read(data, lineSize(qMin(maxLength, size())));
+    }
+
+private:
+    QLinkedList<QByteArray> buffers;
+    int head, tail;
+    int totalSize;
+};
+
+struct KPtyDevicePrivate : public KPtyPrivate {
+    Q_DECLARE_PUBLIC(KPtyDevice)
+
+    KPtyDevicePrivate(KPty* parent) :
+        KPtyPrivate(parent),
+        emittedReadyRead(false), emittedBytesWritten(false),
+        readNotifier(0), writeNotifier(0)
+    {
+    }
+
+    bool _k_canRead();
+    bool _k_canWrite();
+
+    bool doWait(int msecs, bool reading);
+    void finishOpen(QIODevice::OpenMode mode);
+
+    bool emittedReadyRead;
+    bool emittedBytesWritten;
+    QSocketNotifier *readNotifier;
+    QSocketNotifier *writeNotifier;
+    KRingBuffer readBuffer;
+    KRingBuffer writeBuffer;
+};
+
+#endif
+
new file mode 100644
--- /dev/null
+++ b/gui/src/kptyprocess.cpp
@@ -0,0 +1,119 @@
+/*
+
+    This file is part of the KDE libraries
+
+    Copyright (C) 2007 Oswald Buddenhagen <ossi@kde.org>
+
+    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 "kptyprocess.h"
+#include "kprocess.h"
+
+#include "kptydevice.h"
+
+#include <stdlib.h>
+#include <unistd.h>
+
+//////////////////
+// private data //
+//////////////////
+
+KPtyProcess::KPtyProcess(QObject *parent) :
+    KProcess(new KPtyProcessPrivate, parent)
+{
+    Q_D(KPtyProcess);
+
+    d->pty = new KPtyDevice(this);
+    d->pty->open();
+    connect(this, SIGNAL(stateChanged(QProcess::ProcessState)),
+            SLOT(_k_onStateChanged(QProcess::ProcessState)));
+}
+
+KPtyProcess::KPtyProcess(int ptyMasterFd, QObject *parent) :
+    KProcess(new KPtyProcessPrivate, parent)
+{
+    Q_D(KPtyProcess);
+
+    d->pty = new KPtyDevice(this);
+    d->pty->open(ptyMasterFd);
+    connect(this, SIGNAL(stateChanged(QProcess::ProcessState)),
+            SLOT(_k_onStateChanged(QProcess::ProcessState)));
+}
+
+KPtyProcess::~KPtyProcess()
+{
+    Q_D(KPtyProcess);
+
+    if (state() != QProcess::NotRunning && d->addUtmp) {
+        d->pty->logout();
+        disconnect(SIGNAL(stateChanged(QProcess::ProcessState)),
+                   this, SLOT(_k_onStateChanged(QProcess::ProcessState)));
+    }
+    delete d->pty;
+}
+
+void KPtyProcess::setPtyChannels(PtyChannels channels)
+{
+    Q_D(KPtyProcess);
+
+    d->ptyChannels = channels;
+}
+
+KPtyProcess::PtyChannels KPtyProcess::ptyChannels() const
+{
+    Q_D(const KPtyProcess);
+
+    return d->ptyChannels;
+}
+
+void KPtyProcess::setUseUtmp(bool value)
+{
+    Q_D(KPtyProcess);
+
+    d->addUtmp = value;
+}
+
+bool KPtyProcess::isUseUtmp() const
+{
+    Q_D(const KPtyProcess);
+
+    return d->addUtmp;
+}
+
+KPtyDevice *KPtyProcess::pty() const
+{
+    Q_D(const KPtyProcess);
+
+    return d->pty;
+}
+
+void KPtyProcess::setupChildProcess()
+{
+    Q_D(KPtyProcess);
+
+    d->pty->setCTty();
+    if (d->addUtmp)
+      d->pty->login(getenv("USER"), getenv("DISPLAY"));
+      //d->pty->login(KUser(KUser::UseRealUserID).loginName().toLocal8Bit().data(), qgetenv("DISPLAY"));
+    if (d->ptyChannels & StdinChannel)
+        dup2(d->pty->slaveFd(), 0);
+    if (d->ptyChannels & StdoutChannel)
+        dup2(d->pty->slaveFd(), 1);
+    if (d->ptyChannels & StderrChannel)
+        dup2(d->pty->slaveFd(), 2);
+
+    KProcess::setupChildProcess();
+}
new file mode 100644
--- /dev/null
+++ b/gui/src/kptyprocess.h
@@ -0,0 +1,157 @@
+/*
+    This file is part of the KDE libraries
+
+    Copyright (C) 2007 Oswald Buddenhagen <ossi@kde.org>
+
+    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 KPTYPROCESS_H
+#define KPTYPROCESS_H
+
+#include "kprocess.h"
+#include "kprocess_p.h"
+#include "kptydevice.h"
+
+class KPtyDevice;
+class KPtyProcess;
+struct KPtyProcessPrivate;
+
+/**
+ * This class extends KProcess by support for PTYs (pseudo TTYs).
+ *
+ * The PTY is opened as soon as the class is instantiated. Verify that
+ * it was opened successfully by checking that pty()->masterFd() is not -1.
+ *
+ * The PTY is always made the process' controlling TTY.
+ * Utmp registration and connecting the stdio handles to the PTY are optional.
+ *
+ * No attempt to integrate with QProcess' waitFor*() functions was made,
+ * for it is impossible. Note that execute() does not work with the PTY, too.
+ * Use the PTY device's waitFor*() functions or use it asynchronously.
+ *
+ * @author Oswald Buddenhagen <ossi@kde.org>
+ */
+class KPtyProcess : public KProcess
+{
+    Q_OBJECT
+    Q_DECLARE_PRIVATE(KPtyProcess)
+
+public:
+    enum PtyChannelFlag {
+        NoChannels = 0, /**< The PTY is not connected to any channel. */
+        StdinChannel = 1, /**< Connect PTY to stdin. */
+        StdoutChannel = 2, /**< Connect PTY to stdout. */
+        StderrChannel = 4, /**< Connect PTY to stderr. */
+        AllOutputChannels = 6, /**< Connect PTY to all output channels. */
+        AllChannels = 7 /**< Connect PTY to all channels. */
+    };
+
+    Q_DECLARE_FLAGS(PtyChannels, PtyChannelFlag)
+
+    /**
+     * Constructor
+     */
+    explicit KPtyProcess(QObject *parent = 0);
+
+    /**
+     * Construct a process using an open pty master.
+     *
+     * @param ptyMasterFd an open pty master file descriptor.
+     *   The process does not take ownership of the descriptor;
+     *   it will not be automatically closed at any point.
+     */
+    KPtyProcess(int ptyMasterFd, QObject *parent = 0);
+
+    /**
+     * Destructor
+     */
+    virtual ~KPtyProcess();
+
+    /**
+     * Set to which channels the PTY should be assigned.
+     *
+     * This function must be called before starting the process.
+     *
+     * @param channels the output channel handling mode
+     */
+    void setPtyChannels(PtyChannels channels);
+
+    /**
+     * Query to which channels the PTY is assigned.
+     *
+     * @return the output channel handling mode
+     */
+    PtyChannels ptyChannels() const;
+
+    /**
+     * Set whether to register the process as a TTY login in utmp.
+     *
+     * Utmp is disabled by default.
+     * It should enabled for interactively fed processes, like terminal
+     * emulations.
+     *
+     * This function must be called before starting the process.
+     *
+     * @param value whether to register in utmp.
+     */
+    void setUseUtmp(bool value);
+
+    /**
+     * Get whether to register the process as a TTY login in utmp.
+     *
+     * @return whether to register in utmp
+     */
+    bool isUseUtmp() const;
+
+    /**
+     * Get the PTY device of this process.
+     *
+     * @return the PTY device
+     */
+    KPtyDevice *pty() const;
+
+protected:
+    /**
+     * @reimp
+     */
+    virtual void setupChildProcess();
+
+private:
+    Q_PRIVATE_SLOT(d_func(), void _k_onStateChanged(QProcess::ProcessState))
+};
+
+struct KPtyProcessPrivate : KProcessPrivate {
+    KPtyProcessPrivate() :
+        ptyChannels(KPtyProcess::NoChannels),
+        addUtmp(false)
+    {
+    }
+
+    void _k_onStateChanged(QProcess::ProcessState newState)
+    {
+        if (newState == QProcess::NotRunning && addUtmp)
+            pty->logout();
+    }
+
+    KPtyDevice *pty;
+    KPtyProcess::PtyChannels ptyChannels;
+    bool addUtmp : 1;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(KPtyProcess::PtyChannels)
+
+#endif