finally a terminal emulator for efl! sure - uses a lot of text
authorraster <raster@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Tue, 12 Jun 2012 10:10:01 +0000 (10:10 +0000)
committerraster <raster@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Tue, 12 Jun 2012 10:10:01 +0000 (10:10 +0000)
objects. need evas textgrid obj and more, but this marks a first
"usable" state for terminology. more needs doing like underline and
strikethrough support, blink support, visual bell, config panel etc.

git-svn-id: http://svn.enlightenment.org/svn/e/trunk/terminology@72007 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33

40 files changed:
AUTHORS [new file with mode: 0644]
COPYING [new file with mode: 0644]
ChangeLog [new file with mode: 0644]
INSTALL [new file with mode: 0644]
Makefile.am [new file with mode: 0644]
NEWS [new file with mode: 0644]
README [new file with mode: 0644]
autogen.sh [new file with mode: 0755]
configure.ac [new file with mode: 0644]
data/Makefile.am [new file with mode: 0644]
data/desktop/Makefile.am [new file with mode: 0644]
data/desktop/terminology.desktop [new file with mode: 0644]
data/fonts/Makefile.am [new file with mode: 0644]
data/fonts/nex6x10.pcf [new file with mode: 0644]
data/icons/Makefile.am [new file with mode: 0644]
data/icons/terminology.png [new file with mode: 0644]
data/images/Makefile.am [new file with mode: 0644]
data/themes/Makefile.am [new file with mode: 0644]
data/themes/default.edc [new file with mode: 0644]
data/themes/images/Makefile.am [new file with mode: 0644]
data/themes/images/bg_bevel.png [new file with mode: 0644]
data/themes/images/bg_shine.png [new file with mode: 0644]
m4/efl_binary.m4 [new file with mode: 0644]
src/Makefile.am [new file with mode: 0644]
src/bin/Makefile.am [new file with mode: 0644]
src/bin/col.c [new file with mode: 0644]
src/bin/col.h [new file with mode: 0644]
src/bin/config.c [new file with mode: 0644]
src/bin/config.h [new file with mode: 0644]
src/bin/keyin.c [new file with mode: 0644]
src/bin/keyin.h [new file with mode: 0644]
src/bin/main.c [new file with mode: 0644]
src/bin/termio.c [new file with mode: 0644]
src/bin/termio.h [new file with mode: 0644]
src/bin/termpty.c [new file with mode: 0644]
src/bin/termpty.h [new file with mode: 0644]
src/bin/utf8.c [new file with mode: 0644]
src/bin/utf8.h [new file with mode: 0644]
src/bin/win.c [new file with mode: 0644]
src/bin/win.h [new file with mode: 0644]

diff --git a/AUTHORS b/AUTHORS
new file mode 100644 (file)
index 0000000..854dee6
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1 @@
+Carsten Haitzler (Rasterman) <raster@rasterman.com>
diff --git a/COPYING b/COPYING
new file mode 100644 (file)
index 0000000..78c1419
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,357 @@
+Copyright notice for terminology:
+
+Copyright (C) 2012-2012 Carsten Haitzler and various contributors (see AUTHORS)
+
+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; version 2 of the License.
+
+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 Lesser General Public License for more
+details.
+
+Below is a copy of the GNU General Public License that is distributed
+along with this library. If you do not have a copy below, write to the Free
+Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301  USA
+
+                    GNU GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                      59 Temple Place, Suite 330, Boston, MA 02111 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.
+\f
+                   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.)
+\f
+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.
+\f
+  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.
+\f
+  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
+\f
+       Appendix: 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) 19yy  <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 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) 19yy 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.
diff --git a/ChangeLog b/ChangeLog
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/INSTALL b/INSTALL
new file mode 100644 (file)
index 0000000..f67815a
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,11 @@
+COMPILING and INSTALLING:
+
+If you got a official release tar archive do:
+    ./configure
+    
+Then to compile:
+    make
+
+To install (run this as root, or the user who handles installs):
+    make install
+
diff --git a/Makefile.am b/Makefile.am
new file mode 100644 (file)
index 0000000..fafb3a7
--- /dev/null
@@ -0,0 +1,29 @@
+ACLOCAL_AMFLAGS = -I m4
+
+SUBDIRS = src data
+
+MAINTAINERCLEANFILES = \
+Makefile.in \
+$(PACKAGE_TARNAME)-$(PACKAGE_VERSION).tar.gz \
+$(PACKAGE_TARNAME)-$(PACKAGE_VERSION).tar.bz2 \
+aclocal.m4 \
+config.guess \
+terminology_config.h.in \
+config.sub \
+configure \
+compile \
+depcomp \
+install-sh \
+ltconfig \
+ltmain.sh \
+missing \
+mkinstalldirs \
+stamp-h.in \
+stamp-h \
+m4/libtool.m4 \
+m4/lt~obsolete.m4 \
+m4/ltoptions.m4 \
+m4/ltsugar.m4 \
+m4/ltversion.m4
+
+EXTRA_DIST = README AUTHORS COPYING
diff --git a/NEWS b/NEWS
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..d227109
--- /dev/null
+++ b/README
@@ -0,0 +1,23 @@
+Terminology
+-----------
+
+An EFL terminal emtulator
+
+Requiremnents:
+--------------
+
+  * elementary 1.1 (1.0.99 SVN latest)
+  * evas 1.3 (1.2.99 SVN latest)
+  * ecore
+  * edje
+
+Please see http://www.enlightenment.org for information on these.
+
+Compiling:
+----------
+
+Once you have met requirements, compiling and installing is simple:
+
+  ./configure
+  make
+  make install
diff --git a/autogen.sh b/autogen.sh
new file mode 100755 (executable)
index 0000000..31ccda0
--- /dev/null
@@ -0,0 +1,16 @@
+#!/bin/sh
+
+rm -rf autom4te.cache
+rm -f aclocal.m4 ltmain.sh
+
+touch README
+
+echo "Running aclocal..." ; aclocal -I m4 $ACLOCAL_FLAGS || exit 1
+echo "Running autoheader..." ; autoheader || exit 1
+echo "Running autoconf..." ; autoconf || exit 1
+echo "Running libtoolize..." ; (libtoolize --copy --automake || glibtoolize --automake) || exit 1
+echo "Running automake..." ; automake --add-missing --copy --gnu || exit 1
+
+if [ -z "$NOCONFIGURE" ]; then
+       ./configure "$@"
+fi
diff --git a/configure.ac b/configure.ac
new file mode 100644 (file)
index 0000000..05d92dd
--- /dev/null
@@ -0,0 +1,63 @@
+dnl Process this file with autoconf to produce a configure script.
+
+# get rid of that stupid cache mechanism
+rm -f config.cache
+
+AC_INIT([terminology], [0.1.0], [enlightenment-devel@lists.sourceforge.net])
+AC_PREREQ([2.52])
+AC_CONFIG_SRCDIR([configure.ac])
+AC_CONFIG_MACRO_DIR([m4])
+
+AC_CONFIG_HEADERS([terminology_config.h])
+
+AM_INIT_AUTOMAKE([1.6 dist-bzip2])
+m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
+
+AM_PROG_CC_STDC
+AM_PROG_CC_C_O
+
+requirements="\
+   elementary >= 1.0.99 \
+   eina >= 1.2.99 \
+   eet >= 1.6.99 \
+   evas >= 1.2.99 \
+   ecore >= 1.2.99 \
+   edje >= 1.2.99"
+
+PKG_CHECK_MODULES([TERMINOLOGY], [${requirements}])
+
+EFL_WITH_BIN([edje], [edje-cc], [edje_cc])
+
+AC_CONFIG_FILES([
+Makefile
+src/Makefile
+src/bin/Makefile
+data/Makefile
+data/desktop/Makefile
+data/icons/Makefile
+data/images/Makefile
+data/fonts/Makefile
+data/themes/Makefile
+data/themes/images/Makefile
+])
+
+AC_OUTPUT
+
+#####################################################################
+## Info
+
+echo
+echo
+echo
+echo "------------------------------------------------------------------------"
+echo "$PACKAGE $VERSION"
+echo "------------------------------------------------------------------------"
+echo
+echo "Compilation................: make (or gmake)"
+echo "  CPPFLAGS.................: $CPPFLAGS"
+echo "  CFLAGS...................: $CFLAGS"
+echo "  LDFLAGS..................: $LDFLAGS"
+echo
+echo "Installation...............: make install (as root if needed, with 'su' or 'sudo')"
+echo "  prefix...................: $prefix"
+echo
diff --git a/data/Makefile.am b/data/Makefile.am
new file mode 100644 (file)
index 0000000..735ca17
--- /dev/null
@@ -0,0 +1,3 @@
+MAINTAINERCLEANFILES = Makefile.in
+SUBDIRS = desktop icons images fonts themes
+
diff --git a/data/desktop/Makefile.am b/data/desktop/Makefile.am
new file mode 100644 (file)
index 0000000..e9d5fe6
--- /dev/null
@@ -0,0 +1,6 @@
+MAINTAINERCLEANFILES = Makefile.in
+filesdir = $(datadir)/applications
+files_DATA = \
+terminology.desktop
+
+EXTRA_DIST = $(files_DATA)
diff --git a/data/desktop/terminology.desktop b/data/desktop/terminology.desktop
new file mode 100644 (file)
index 0000000..0e7236b
--- /dev/null
@@ -0,0 +1,11 @@
+[Desktop Entry]
+Encoding=UTF-8
+Type=Application
+Name=Terminology
+Generic=Terminal
+Comment=Terminal emulator
+Exec=terminology
+Icon=terminology.png
+Categories=Utility;TerminalEmulator;
+Terminal=false
+StartupWMClass=terminology
diff --git a/data/fonts/Makefile.am b/data/fonts/Makefile.am
new file mode 100644 (file)
index 0000000..b122ede
--- /dev/null
@@ -0,0 +1,6 @@
+MAINTAINERCLEANFILES = Makefile.in
+filesdir = $(pkgdatadir)/fonts
+files_DATA = \
+nex6x10.pcf
+
+EXTRA_DIST = $(files_DATA)
diff --git a/data/fonts/nex6x10.pcf b/data/fonts/nex6x10.pcf
new file mode 100644 (file)
index 0000000..f41a5c6
Binary files /dev/null and b/data/fonts/nex6x10.pcf differ
diff --git a/data/icons/Makefile.am b/data/icons/Makefile.am
new file mode 100644 (file)
index 0000000..e712906
--- /dev/null
@@ -0,0 +1,6 @@
+MAINTAINERCLEANFILES = Makefile.in
+filesdir = $(datadir)/icons
+files_DATA = \
+terminology.png
+
+EXTRA_DIST = $(files_DATA)
diff --git a/data/icons/terminology.png b/data/icons/terminology.png
new file mode 100644 (file)
index 0000000..fca757a
Binary files /dev/null and b/data/icons/terminology.png differ
diff --git a/data/images/Makefile.am b/data/images/Makefile.am
new file mode 100644 (file)
index 0000000..411e19c
--- /dev/null
@@ -0,0 +1,5 @@
+MAINTAINERCLEANFILES = Makefile.in
+filesdir = $(pkgdatadir)/images
+files_DATA =
+
+EXTRA_DIST = $(files_DATA)
diff --git a/data/themes/Makefile.am b/data/themes/Makefile.am
new file mode 100644 (file)
index 0000000..6125a54
--- /dev/null
@@ -0,0 +1,23 @@
+MAINTAINERCLEANFILES = Makefile.in
+
+SUBDIRS = images
+
+EDJE_CC = @edje_cc@
+EDJE_FLAGS_VERBOSE_ =
+EDJE_FLAGS_VERBOSE_0 =
+EDJE_FLAGS_VERBOSE_1 = -v
+EDJE_FLAGS = $(EDJE_FLAGS_$(V)) -id $(top_srcdir)/data/themes/images -fd $(top_srcdir)/data/fonts
+
+filesdir = $(pkgdatadir)/themes
+files_DATA = \
+default.edj
+
+EXTRA_DIST = default.edc
+
+default.edj: Makefile default.edc
+       $(EDJE_CC) $(EDJE_FLAGS) \
+       $(top_srcdir)/data/themes/default.edc \
+       $(top_builddir)/data/themes/default.edj
+
+clean-local:
+       rm -f *.edj
diff --git a/data/themes/default.edc b/data/themes/default.edc
new file mode 100644 (file)
index 0000000..cc6fc01
--- /dev/null
@@ -0,0 +1,91 @@
+collections {
+   group { name: "terminology/background";
+      images {
+        image: "bg_bevel.png" COMP;
+        image: "bg_shine.png" COMP;
+      }
+      parts {
+         part { name: "base"; type: RECT;
+            mouse_events: 1;
+            description { state: "default" 0.0;
+               color: 48 48 48 255;
+            }
+         }
+         part { name: "terminology.content"; type: SWALLOW;
+            description { state: "default" 0.0;
+               rel1.offset: 1 2;
+               rel2.offset: -2 -2;
+            }
+         }
+         part { name: "bevel";
+            mouse_events: 0;
+            description { state: "default" 0.0;
+               rel1.offset: 0 1;
+               rel2.offset: -1 -1;
+               image.normal: "bg_bevel.png";
+               image.border: 2 2 2 2;
+               image.middle: 0;
+               fill.smooth: 0;
+            }
+         }
+         part { name: "shine";
+            mouse_events: 0;
+            description { state: "default" 0.0;
+               rel1.offset: 0 1;
+               rel2.offset: -1 -1;
+               image.normal: "bg_shine.png";
+               align: 0.5 0.0;
+               aspect: (255/120) (255/120);
+               aspect_preference: HORIZONTAL;
+            }
+         }
+      }
+   }
+   group { name: "terminology/cursor";
+      parts {
+         part { name: "base"; type: RECT;
+            mouse_events: 1;
+            description { state: "default" 0.0;
+               color: 255 255 255 30;
+            }
+            description { state: "focused" 0.0;
+               color: 255 255 255 160;
+            }
+         }
+         programs {
+            program { name: "focus_in";
+               signal: "focus,in";
+               source: "terminology";
+               action: STATE_SET "focused" 0.0;
+               target: "base";
+               after: "focus2";
+            }
+            program { name: "focus2";
+               in: 0.2 0.0;
+               action: STATE_SET "default" 0.0;
+               target: "base";
+               after: "focus3";
+            }
+            program { name: "focus3";
+               in: 0.2 0.0;
+               action: STATE_SET "focused" 0.0;
+               target: "base";
+               after: "focus2";
+            }
+            program { name: "focus_out";
+               signal: "focus,out";
+               source: "terminology";
+               action: ACTION_STOP;
+               target: "focus_in";
+               target: "focus2";
+               target: "focus3";
+               after: "focus_out2";
+            }
+            program { name: "focus_out2";
+               action: STATE_SET "default" 0.0;
+               target: "base";
+            }
+         }
+      }
+   }
+}
diff --git a/data/themes/images/Makefile.am b/data/themes/images/Makefile.am
new file mode 100644 (file)
index 0000000..f4f40d0
--- /dev/null
@@ -0,0 +1,4 @@
+MAINTAINERCLEANFILES = Makefile.in
+EXTRA_DIST = \
+bg_bevel.png \
+bg_shine.png
diff --git a/data/themes/images/bg_bevel.png b/data/themes/images/bg_bevel.png
new file mode 100644 (file)
index 0000000..87e4d62
Binary files /dev/null and b/data/themes/images/bg_bevel.png differ
diff --git a/data/themes/images/bg_shine.png b/data/themes/images/bg_shine.png
new file mode 100644 (file)
index 0000000..47e5280
Binary files /dev/null and b/data/themes/images/bg_shine.png differ
diff --git a/m4/efl_binary.m4 b/m4/efl_binary.m4
new file mode 100644 (file)
index 0000000..c774688
--- /dev/null
@@ -0,0 +1,71 @@
+dnl Copyright (C) 2010 Vincent Torri <vtorri at univ-evry dot fr>
+dnl That code is public domain and can be freely used or copied.
+
+dnl Macro that check if a binary is built or not
+
+dnl Usage: EFL_ENABLE_BIN(binary)
+dnl Call AC_SUBST(BINARY_PRG) (BINARY is the uppercase of binary, - being transformed into _)
+dnl Define have_binary (- is transformed into _)
+dnl Define conditional BUILD_BINARY (BINARY is the uppercase of binary, - being transformed into _)
+
+AC_DEFUN([EFL_ENABLE_BIN],
+[
+
+m4_pushdef([UP], m4_translit([[$1]], [-a-z], [_A-Z]))dnl
+m4_pushdef([DOWN], m4_translit([[$1]], [-A-Z], [_a-z]))dnl
+
+have_[]m4_defn([DOWN])="yes"
+
+dnl configure option
+
+AC_ARG_ENABLE([$1],
+   [AC_HELP_STRING([--disable-$1], [disable building of ]DOWN)],
+   [
+    if test "x${enableval}" = "xyes" ; then
+       have_[]m4_defn([DOWN])="yes"
+    else
+       have_[]m4_defn([DOWN])="no"
+    fi
+   ])
+
+AC_MSG_CHECKING([whether to build ]DOWN[ binary])
+AC_MSG_RESULT([$have_[]m4_defn([DOWN])])
+
+if test "x$have_[]m4_defn([DOWN])" = "xyes"; then
+   UP[]_PRG=DOWN[${EXEEXT}]
+fi
+
+AC_SUBST(UP[]_PRG)
+
+AM_CONDITIONAL(BUILD_[]UP, test "x$have_[]m4_defn([DOWN])" = "xyes")
+
+AS_IF([test "x$have_[]m4_defn([DOWN])" = "xyes"], [$2], [$3])
+
+])
+
+
+dnl Macro that check if a binary is built or not
+
+dnl Usage: EFL_WITH_BIN(package, binary, default_value)
+dnl Call AC_SUBST(_binary) (_binary is the lowercase of binary, - being transformed into _ by default, or the value set by the user)
+
+AC_DEFUN([EFL_WITH_BIN],
+[
+
+m4_pushdef([DOWN], m4_translit([[$2]], [-A-Z], [_a-z]))dnl
+
+dnl configure option
+
+AC_ARG_WITH([$2],
+   [AC_HELP_STRING([--with-$2=PATH], [specify a specific path to ]DOWN[ @<:@default=$3@:>@])],
+   [_efl_with_binary=${withval}],
+   [_efl_with_binary=$(pkg-config --variable=prefix $1)/bin/$3])
+
+DOWN=${_efl_with_binary}
+AC_MSG_NOTICE(DOWN[ set to ${_efl_with_binary}])
+
+with_binary_[]m4_defn([DOWN])=${_efl_with_binary}
+
+AC_SUBST(DOWN)
+
+])
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644 (file)
index 0000000..ccfbf1a
--- /dev/null
@@ -0,0 +1,2 @@
+MAINTAINERCLEANFILES = Makefile.in
+SUBDIRS = bin
diff --git a/src/bin/Makefile.am b/src/bin/Makefile.am
new file mode 100644 (file)
index 0000000..02f8496
--- /dev/null
@@ -0,0 +1,19 @@
+MAINTAINERCLEANFILES = Makefile.in
+
+bin_PROGRAMS = terminology
+
+terminology_CPPFLAGS = -I. \
+-DPACKAGE_BIN_DIR=\"$(bindir)\" -DPACKAGE_LIB_DIR=\"$(libdir)\" \
+-DPACKAGE_DATA_DIR=\"$(pkgdatadir)\" @TERMINOLOGY_CFLAGS@
+
+terminology_LDADD = @TERMINOLOGY_LIBS@
+
+terminology_SOURCES = \
+col.c col.h \
+config.c config.h \
+keyin.c keyin.h \
+main.c \
+termio.c termio.h \
+termpty.c termpty.h \
+utf8.c utf8.h \
+win.c win.h
diff --git a/src/bin/col.c b/src/bin/col.c
new file mode 100644 (file)
index 0000000..3268082
--- /dev/null
@@ -0,0 +1,332 @@
+#include "col.h"
+
+const Color colors[2][11] =
+{
+   { // normal
+        { 0xaa, 0xaa, 0xaa, 0xff }, // COL_DEF
+        { 0x00, 0x00, 0x00, 0xff }, // COL_BLACK
+        { 0xcc, 0x33, 0x33, 0xff }, // COL_RED
+        { 0x33, 0xcc, 0x33, 0xff }, // COL_GREEN
+        { 0xcc, 0x88, 0x33, 0xff }, // COL_YELLOW
+        { 0x33, 0x33, 0xcc, 0xff }, // COL_BLUE
+        { 0xcc, 0x33, 0xcc, 0xff }, // COL_MAGENTA
+        { 0x33, 0xcc, 0xcc, 0xff }, // COL_CYAN
+        { 0xcc, 0xcc, 0xcc, 0xff }, // COL_WHITE
+        { 0x22, 0x22, 0x22, 0xff }, // COL_INVERSE
+        { 0xaa, 0xaa, 0xaa, 0xff }, // COL_INVERSEBG
+   },
+   { // bright/bold
+        { 0xee, 0xee, 0xee, 0xff }, // COL_DEF
+        { 0x66, 0x66, 0x66, 0xff }, // COL_BLACK
+        { 0xff, 0x66, 0x66, 0xff }, // COL_RED
+        { 0x66, 0xff, 0x66, 0xff }, // COL_GREEN
+        { 0xff, 0xff, 0x66, 0xff }, // COL_YELLOW
+        { 0x66, 0x66, 0xff, 0xff }, // COL_BLUE
+        { 0xff, 0x66, 0xff, 0xff }, // COL_MAGENTA
+        { 0x66, 0xff, 0xff, 0xff }, // COL_CYAN
+        { 0xff, 0xff, 0xff, 0xff }, // COL_WHITE
+        { 0x11, 0x11, 0x11, 0xff }, // COL_INVERSE
+        { 0xee, 0xee, 0xee, 0xff }, // COL_INVERSEBG
+   }
+};
+
+const Color colors256[256] =
+{
+   // basic 16 repeated
+   { 0x00, 0x00, 0x00, 0xff }, // COL_BLACK
+   { 0xcc, 0x33, 0x33, 0xff }, // COL_RED
+   { 0x33, 0xcc, 0x33, 0xff }, // COL_GREEN
+   { 0xcc, 0x88, 0x33, 0xff }, // COL_YELLOW
+   { 0x33, 0x33, 0xcc, 0xff }, // COL_BLUE
+   { 0xcc, 0x33, 0xcc, 0xff }, // COL_MAGENTA
+   { 0x33, 0xcc, 0xcc, 0xff }, // COL_CYAN
+   { 0xcc, 0xcc, 0xcc, 0xff }, // COL_WHITE
+   
+   { 0x66, 0x66, 0x66, 0xff }, // COL_BLACK
+   { 0xff, 0x66, 0x66, 0xff }, // COL_RED
+   { 0x66, 0xff, 0x66, 0xff }, // COL_GREEN
+   { 0xff, 0xff, 0x66, 0xff }, // COL_YELLOW
+   { 0x66, 0x66, 0xff, 0xff }, // COL_BLUE
+   { 0xff, 0x66, 0xff, 0xff }, // COL_MAGENTA
+   { 0x66, 0xff, 0xff, 0xff }, // COL_CYAN
+   { 0xff, 0xff, 0xff, 0xff }, // COL_WHITE
+   
+   // pure 6x6x6 colorcube
+   { 0x00, 0x00, 0x00, 0xff },
+   { 0x00, 0x00, 0x5f, 0xff },
+   { 0x00, 0x00, 0x87, 0xff },
+   { 0x00, 0x00, 0xaf, 0xff },
+   { 0x00, 0x00, 0xd7, 0xff },
+   { 0x00, 0x00, 0xff, 0xff },
+   
+   { 0x00, 0x5f, 0x00, 0xff },
+   { 0x00, 0x5f, 0x5f, 0xff },
+   { 0x00, 0x5f, 0x87, 0xff },
+   { 0x00, 0x5f, 0xaf, 0xff },
+   { 0x00, 0x5f, 0xd7, 0xff },
+   { 0x00, 0x5f, 0xff, 0xff },
+   
+   { 0x00, 0x87, 0x00, 0xff },
+   { 0x00, 0x87, 0x5f, 0xff },
+   { 0x00, 0x87, 0x87, 0xff },
+   { 0x00, 0x87, 0xaf, 0xff },
+   { 0x00, 0x87, 0xd7, 0xff },
+   { 0x00, 0x87, 0xff, 0xff },
+   
+   { 0x00, 0xaf, 0x00, 0xff },
+   { 0x00, 0xaf, 0x5f, 0xff },
+   { 0x00, 0xaf, 0x87, 0xff },
+   { 0x00, 0xaf, 0xaf, 0xff },
+   { 0x00, 0xaf, 0xd7, 0xff },
+   { 0x00, 0xaf, 0xff, 0xff },
+   
+   { 0x00, 0xd7, 0x00, 0xff },
+   { 0x00, 0xd7, 0x5f, 0xff },
+   { 0x00, 0xd7, 0x87, 0xff },
+   { 0x00, 0xd7, 0xaf, 0xff },
+   { 0x00, 0xd7, 0xd7, 0xff },
+   { 0x00, 0xd7, 0xff, 0xff },
+   
+   { 0x00, 0xff, 0x00, 0xff },
+   { 0x00, 0xff, 0x5f, 0xff },
+   { 0x00, 0xff, 0x87, 0xff },
+   { 0x00, 0xff, 0xaf, 0xff },
+   { 0x00, 0xff, 0xd7, 0xff },
+   { 0x00, 0xff, 0xff, 0xff },
+   
+   { 0x5f, 0x00, 0x00, 0xff },
+   { 0x5f, 0x00, 0x5f, 0xff },
+   { 0x5f, 0x00, 0x87, 0xff },
+   { 0x5f, 0x00, 0xaf, 0xff },
+   { 0x5f, 0x00, 0xd7, 0xff },
+   { 0x5f, 0x00, 0xff, 0xff },
+   
+   { 0x5f, 0x5f, 0x00, 0xff },
+   { 0x5f, 0x5f, 0x5f, 0xff },
+   { 0x5f, 0x5f, 0x87, 0xff },
+   { 0x5f, 0x5f, 0xaf, 0xff },
+   { 0x5f, 0x5f, 0xd7, 0xff },
+   { 0x5f, 0x5f, 0xff, 0xff },
+   
+   { 0x5f, 0x87, 0x00, 0xff },
+   { 0x5f, 0x87, 0x5f, 0xff },
+   { 0x5f, 0x87, 0x87, 0xff },
+   { 0x5f, 0x87, 0xaf, 0xff },
+   { 0x5f, 0x87, 0xd7, 0xff },
+   { 0x5f, 0x87, 0xff, 0xff },
+   
+   { 0x5f, 0xaf, 0x00, 0xff },
+   { 0x5f, 0xaf, 0x5f, 0xff },
+   { 0x5f, 0xaf, 0x87, 0xff },
+   { 0x5f, 0xaf, 0xaf, 0xff },
+   { 0x5f, 0xaf, 0xd7, 0xff },
+   { 0x5f, 0xaf, 0xff, 0xff },
+   
+   { 0x5f, 0xd7, 0x00, 0xff },
+   { 0x5f, 0xd7, 0x5f, 0xff },
+   { 0x5f, 0xd7, 0x87, 0xff },
+   { 0x5f, 0xd7, 0xaf, 0xff },
+   { 0x5f, 0xd7, 0xd7, 0xff },
+   { 0x5f, 0xd7, 0xff, 0xff },
+   
+   { 0x5f, 0xff, 0x00, 0xff },
+   { 0x5f, 0xff, 0x5f, 0xff },
+   { 0x5f, 0xff, 0x87, 0xff },
+   { 0x5f, 0xff, 0xaf, 0xff },
+   { 0x5f, 0xff, 0xd7, 0xff },
+   { 0x5f, 0xff, 0xff, 0xff },
+   
+   { 0x87, 0x00, 0x00, 0xff },
+   { 0x87, 0x00, 0x5f, 0xff },
+   { 0x87, 0x00, 0x87, 0xff },
+   { 0x87, 0x00, 0xaf, 0xff },
+   { 0x87, 0x00, 0xd7, 0xff },
+   { 0x87, 0x00, 0xff, 0xff },
+   
+   { 0x87, 0x5f, 0x00, 0xff },
+   { 0x87, 0x5f, 0x5f, 0xff },
+   { 0x87, 0x5f, 0x87, 0xff },
+   { 0x87, 0x5f, 0xaf, 0xff },
+   { 0x87, 0x5f, 0xd7, 0xff },
+   { 0x87, 0x5f, 0xff, 0xff },
+   
+   { 0x87, 0x87, 0x00, 0xff },
+   { 0x87, 0x87, 0x5f, 0xff },
+   { 0x87, 0x87, 0x87, 0xff },
+   { 0x87, 0x87, 0xaf, 0xff },
+   { 0x87, 0x87, 0xd7, 0xff },
+   { 0x87, 0x87, 0xff, 0xff },
+   
+   { 0x87, 0xaf, 0x00, 0xff },
+   { 0x87, 0xaf, 0x5f, 0xff },
+   { 0x87, 0xaf, 0x87, 0xff },
+   { 0x87, 0xaf, 0xaf, 0xff },
+   { 0x87, 0xaf, 0xd7, 0xff },
+   { 0x87, 0xaf, 0xff, 0xff },
+   
+   { 0x87, 0xd7, 0x00, 0xff },
+   { 0x87, 0xd7, 0x5f, 0xff },
+   { 0x87, 0xd7, 0x87, 0xff },
+   { 0x87, 0xd7, 0xaf, 0xff },
+   { 0x87, 0xd7, 0xd7, 0xff },
+   { 0x87, 0xd7, 0xff, 0xff },
+   
+   { 0x87, 0xff, 0x00, 0xff },
+   { 0x87, 0xff, 0x5f, 0xff },
+   { 0x87, 0xff, 0x87, 0xff },
+   { 0x87, 0xff, 0xaf, 0xff },
+   { 0x87, 0xff, 0xd7, 0xff },
+   { 0x87, 0xff, 0xff, 0xff },
+   
+   { 0xaf, 0x00, 0x00, 0xff },
+   { 0xaf, 0x00, 0x5f, 0xff },
+   { 0xaf, 0x00, 0x87, 0xff },
+   { 0xaf, 0x00, 0xaf, 0xff },
+   { 0xaf, 0x00, 0xd7, 0xff },
+   { 0xaf, 0x00, 0xff, 0xff },
+   
+   { 0xaf, 0x5f, 0x00, 0xff },
+   { 0xaf, 0x5f, 0x5f, 0xff },
+   { 0xaf, 0x5f, 0x87, 0xff },
+   { 0xaf, 0x5f, 0xaf, 0xff },
+   { 0xaf, 0x5f, 0xd7, 0xff },
+   { 0xaf, 0x5f, 0xff, 0xff },
+   
+   { 0xaf, 0x87, 0x00, 0xff },
+   { 0xaf, 0x87, 0x5f, 0xff },
+   { 0xaf, 0x87, 0x87, 0xff },
+   { 0xaf, 0x87, 0xaf, 0xff },
+   { 0xaf, 0x87, 0xd7, 0xff },
+   { 0xaf, 0x87, 0xff, 0xff },
+   
+   { 0xaf, 0xaf, 0x00, 0xff },
+   { 0xaf, 0xaf, 0x5f, 0xff },
+   { 0xaf, 0xaf, 0x87, 0xff },
+   { 0xaf, 0xaf, 0xaf, 0xff },
+   { 0xaf, 0xaf, 0xd7, 0xff },
+   { 0xaf, 0xaf, 0xff, 0xff },
+   
+   { 0xaf, 0xd7, 0x00, 0xff },
+   { 0xaf, 0xd7, 0x5f, 0xff },
+   { 0xaf, 0xd7, 0x87, 0xff },
+   { 0xaf, 0xd7, 0xaf, 0xff },
+   { 0xaf, 0xd7, 0xd7, 0xff },
+   { 0xaf, 0xd7, 0xff, 0xff },
+   
+   { 0xaf, 0xff, 0x00, 0xff },
+   { 0xaf, 0xff, 0x5f, 0xff },
+   { 0xaf, 0xff, 0x87, 0xff },
+   { 0xaf, 0xff, 0xaf, 0xff },
+   { 0xaf, 0xff, 0xd7, 0xff },
+   { 0xaf, 0xff, 0xff, 0xff },
+   
+   { 0xd7, 0x00, 0x00, 0xff },
+   { 0xd7, 0x00, 0x5f, 0xff },
+   { 0xd7, 0x00, 0x87, 0xff },
+   { 0xd7, 0x00, 0xaf, 0xff },
+   { 0xd7, 0x00, 0xd7, 0xff },
+   { 0xd7, 0x00, 0xff, 0xff },
+   
+   { 0xd7, 0x5f, 0x00, 0xff },
+   { 0xd7, 0x5f, 0x5f, 0xff },
+   { 0xd7, 0x5f, 0x87, 0xff },
+   { 0xd7, 0x5f, 0xaf, 0xff },
+   { 0xd7, 0x5f, 0xd7, 0xff },
+   { 0xd7, 0x5f, 0xff, 0xff },
+   
+   { 0xd7, 0x87, 0x00, 0xff },
+   { 0xd7, 0x87, 0x5f, 0xff },
+   { 0xd7, 0x87, 0x87, 0xff },
+   { 0xd7, 0x87, 0xaf, 0xff },
+   { 0xd7, 0x87, 0xd7, 0xff },
+   { 0xd7, 0x87, 0xff, 0xff },
+   
+   { 0xd7, 0xaf, 0x00, 0xff },
+   { 0xd7, 0xaf, 0x5f, 0xff },
+   { 0xd7, 0xaf, 0x87, 0xff },
+   { 0xd7, 0xaf, 0xaf, 0xff },
+   { 0xd7, 0xaf, 0xd7, 0xff },
+   { 0xd7, 0xaf, 0xff, 0xff },
+   
+   { 0xd7, 0xd7, 0x00, 0xff },
+   { 0xd7, 0xd7, 0x5f, 0xff },
+   { 0xd7, 0xd7, 0x87, 0xff },
+   { 0xd7, 0xd7, 0xaf, 0xff },
+   { 0xd7, 0xd7, 0xd7, 0xff },
+   { 0xd7, 0xd7, 0xff, 0xff },
+   
+   { 0xd7, 0xff, 0x00, 0xff },
+   { 0xd7, 0xff, 0x5f, 0xff },
+   { 0xd7, 0xff, 0x87, 0xff },
+   { 0xd7, 0xff, 0xaf, 0xff },
+   { 0xd7, 0xff, 0xd7, 0xff },
+   { 0xd7, 0xff, 0xff, 0xff },
+   
+   { 0xff, 0x00, 0x00, 0xff },
+   { 0xff, 0x00, 0x5f, 0xff },
+   { 0xff, 0x00, 0x87, 0xff },
+   { 0xff, 0x00, 0xaf, 0xff },
+   { 0xff, 0x00, 0xd7, 0xff },
+   { 0xff, 0x00, 0xff, 0xff },
+   
+   { 0xff, 0x5f, 0x00, 0xff },
+   { 0xff, 0x5f, 0x5f, 0xff },
+   { 0xff, 0x5f, 0x87, 0xff },
+   { 0xff, 0x5f, 0xaf, 0xff },
+   { 0xff, 0x5f, 0xd7, 0xff },
+   { 0xff, 0x5f, 0xff, 0xff },
+   
+   { 0xff, 0x87, 0x00, 0xff },
+   { 0xff, 0x87, 0x5f, 0xff },
+   { 0xff, 0x87, 0x87, 0xff },
+   { 0xff, 0x87, 0xaf, 0xff },
+   { 0xff, 0x87, 0xd7, 0xff },
+   { 0xff, 0x87, 0xff, 0xff },
+   
+   { 0xff, 0xaf, 0x00, 0xff },
+   { 0xff, 0xaf, 0x5f, 0xff },
+   { 0xff, 0xaf, 0x87, 0xff },
+   { 0xff, 0xaf, 0xaf, 0xff },
+   { 0xff, 0xaf, 0xd7, 0xff },
+   { 0xff, 0xaf, 0xff, 0xff },
+   
+   { 0xff, 0xd7, 0x00, 0xff },
+   { 0xff, 0xd7, 0x5f, 0xff },
+   { 0xff, 0xd7, 0x87, 0xff },
+   { 0xff, 0xd7, 0xaf, 0xff },
+   { 0xff, 0xd7, 0xd7, 0xff },
+   { 0xff, 0xd7, 0xff, 0xff },
+   
+   { 0xff, 0xff, 0x00, 0xff },
+   { 0xff, 0xff, 0x5f, 0xff },
+   { 0xff, 0xff, 0x87, 0xff },
+   { 0xff, 0xff, 0xaf, 0xff },
+   { 0xff, 0xff, 0xd7, 0xff },
+   { 0xff, 0xff, 0xff, 0xff },
+
+   // greyscale ramp (24 not including black and white, so 26 if included)
+   { 0x08, 0x08, 0x08, 0xff },
+   { 0x12, 0x12, 0x12, 0xff },
+   { 0x1c, 0x1c, 0x1c, 0xff },
+   { 0x26, 0x26, 0x26, 0xff },
+   { 0x30, 0x30, 0x30, 0xff },
+   { 0x3a, 0x3a, 0x3a, 0xff },
+   { 0x44, 0x44, 0x44, 0xff },
+   { 0x4e, 0x4e, 0x4e, 0xff },
+   { 0x58, 0x58, 0x58, 0xff },
+   { 0x62, 0x62, 0x62, 0xff },
+   { 0x6c, 0x6c, 0x6c, 0xff },
+   { 0x76, 0x76, 0x76, 0xff },
+   { 0x80, 0x80, 0x80, 0xff },
+   { 0x8a, 0x8a, 0x8a, 0xff },
+   { 0x94, 0x94, 0x94, 0xff },
+   { 0x9e, 0x9e, 0x9e, 0xff },
+   { 0xa8, 0xa8, 0xa8, 0xff },
+   { 0xb2, 0xb2, 0xb2, 0xff },
+   { 0xbc, 0xbc, 0xbc, 0xff },
+   { 0xc6, 0xc6, 0xc6, 0xff },
+   { 0xd0, 0xd0, 0xd0, 0xff },
+   { 0xda, 0xda, 0xda, 0xff },
+   { 0xe4, 0xe4, 0xe4, 0xff },
+   { 0xee, 0xee, 0xee, 0xff },
+};
diff --git a/src/bin/col.h b/src/bin/col.h
new file mode 100644 (file)
index 0000000..828e957
--- /dev/null
@@ -0,0 +1,9 @@
+typedef struct _Color Color;
+
+struct _Color
+{
+   unsigned char r, g, b, a;
+};
+
+extern const Color colors[2][11];
+extern const Color colors256[256];
diff --git a/src/bin/config.c b/src/bin/config.c
new file mode 100644 (file)
index 0000000..0db18ab
--- /dev/null
@@ -0,0 +1,24 @@
+#include <Elementary.h>
+#include "config.h"
+
+Config *config = NULL;
+
+void
+config_init(void)
+{
+   config = calloc(1, sizeof(Config));
+//   config->font.bitmap = 0;
+//   config->font.name = eina_stringshare_add("Monospace");
+   config->font.bitmap = 1;
+   config->font.name = eina_stringshare_add("nex6x10.pcf");
+   config->font.size = 10;
+   config->scrollback = 4096;
+   config->theme = "default.edj";
+   config->jump_on_change = 1;
+   config->wordsep = "'\"()[]{}=*!#$^\\:;,?` ";
+}
+
+void
+config_shutdown(void)
+{
+}
diff --git a/src/bin/config.h b/src/bin/config.h
new file mode 100644 (file)
index 0000000..a52e65b
--- /dev/null
@@ -0,0 +1,20 @@
+typedef struct _Config Config;
+
+struct _Config
+{
+   struct {
+      const char    *name;
+      int            size;
+      unsigned char  bitmap;
+   } font;
+   int               scrollback;
+   const char       *theme;
+   unsigned char     jump_on_change;
+   const char       *wordsep;
+};
+
+extern Config *config;
+
+void config_init(void);
+void config_shutdown(void);
+    
diff --git a/src/bin/keyin.c b/src/bin/keyin.c
new file mode 100644 (file)
index 0000000..034ff60
--- /dev/null
@@ -0,0 +1,222 @@
+#include <Elementary.h>
+#include "termpty.h"
+#include "keyin.h"
+
+typedef struct _Keyout Keyout;
+
+struct _Keyout
+{
+   const char *in;
+   const char *out;
+   int         outlen;
+};
+
+#define KEY(in, out) {in, out, sizeof(out) - 1}
+
+static const Keyout crlf_keyout[] =
+{
+   KEY("Return",       "\r\n"),
+   
+   KEY(NULL, "END")
+};
+
+static const Keyout nocrlf_keyout[] =
+{
+   KEY("Return",       "\r"),
+   
+   KEY(NULL, "END")
+};
+
+static const Keyout appcur_keyout[] =
+{
+   KEY("Left",         "\033OD"),
+   KEY("Right",        "\033OC"),
+   KEY("Up",           "\033OA"),
+   KEY("Down",         "\033OB"),
+   
+   KEY(NULL, "END")
+};
+
+static const Keyout keyout[] =
+{
+   KEY("BackSpace",    "\177"),
+//   KEY("BackSpace",    "\b"),
+   KEY("Left",         "\033[D"),
+   KEY("Right",        "\033[C"),
+   KEY("Up",           "\033[A"),
+   KEY("Down",         "\033[B"),
+//   KEY("Tab",          "\t"),
+//   KEY("ISO_Left_Tab", "\t"),
+   KEY("Home",         "\033[7~"),
+   KEY("End",          "\033[8~"),
+   KEY("Prior",        "\033[5~"),
+   KEY("Next",         "\033[6~"),
+   KEY("Insert",       "\033[2~"),
+   KEY("Delete",       "\033[3~"),
+   KEY("Menu",         "\033[29~"),
+   KEY("Find",         "\033[1~"),
+   KEY("Help",         "\033[28~"),
+   KEY("Execute",      "\033[3~"),
+   KEY("Select",       "\033[4~"),
+   KEY("F1",           "\033[11~"),
+   KEY("F2",           "\033[12~"),
+   KEY("F3",           "\033[13~"),
+   KEY("F4",           "\033[14~"),
+   KEY("F5",           "\033[15~"),
+   KEY("F6",           "\033[17~"),
+   KEY("F7",           "\033[18~"),
+   KEY("F8",           "\033[19~"),
+   KEY("F9",           "\033[20~"),
+   KEY("F10",          "\033[21~"),
+   KEY("F11",          "\033[23~"),
+   KEY("F12",          "\033[24~"),
+   KEY("F13",          "\033[25~"),
+   KEY("F14",          "\033[26~"),
+   KEY("F15",          "\033[28~"),
+   KEY("F16",          "\033[29~"),
+   KEY("F17",          "\033[31~"),
+   KEY("F18",          "\033[32~"),
+   KEY("F19",          "\033[33~"),
+   KEY("F20",          "\033[34~"),
+   KEY("F21",          "\033[35~"),
+   KEY("F22",          "\033[36~"),
+   KEY("F23",          "\033[37~"),
+   KEY("F24",          "\033[38~"),
+   KEY("F25",          "\033[39~"),
+   KEY("F26",          "\033[40~"),
+   KEY("F27",          "\033[41~"),
+   KEY("F28",          "\033[42~"),
+   KEY("F29",          "\033[43~"),
+   KEY("F30",          "\033[44~"),
+   KEY("F31",          "\033[45~"),
+   KEY("F32",          "\033[46~"),
+   KEY("F33",          "\033[47~"),
+   KEY("F34",          "\033[48~"),
+   KEY("F35",          "\033[49~"),
+   KEY("KP_F1",        "\033OP"),
+   KEY("KP_F2",        "\033OQ"),
+   KEY("KP_F3",        "\033OR"),
+   KEY("KP_F4",        "\033OS"),
+   KEY("KP_Begin",     "\033Ou"),
+   KEY("KP_Multiply",  "\033Oj"),
+   KEY("KP_Add",       "\033Ok"),
+   KEY("KP_Separator", "\033Ol"),
+   KEY("KP_Subtract",  "\033Om"),
+   KEY("KP_Decimal",   "\033On"),
+   KEY("KP_Divide",    "\033Oo"),
+   KEY("KP_0",         "\033Op"),
+   KEY("KP_0",         "\033Oq"),
+   KEY("KP_0",         "\033Or"),
+   KEY("KP_0",         "\033Os"),
+   KEY("KP_0",         "\033Ot"),
+   KEY("KP_0",         "\033Ou"),
+   KEY("KP_0",         "\033Ov"),
+   KEY("KP_0",         "\033Ow"),
+   KEY("KP_0",         "\033Ox"),
+   KEY("KP_0",         "\033Oy"),
+   
+   KEY(NULL, "END")
+};
+
+static const Keyout kp_keyout[] =
+{
+   KEY("KP_Left",         "\033[D"),
+   KEY("KP_Right",        "\033[C"),
+   KEY("KP_Up",           "\033[A"),
+   KEY("KP_Down",         "\033[B"),
+   KEY("KP_Home",         "\033[7~"),
+   KEY("KP_End",          "\033[8~"),
+   KEY("KP_Prior",        "\033[5~"),
+   KEY("KP_Next",         "\033[6~"),
+   KEY("KP_Insert",       "\033[2~"),
+   KEY("KP_Delete",       "\033[3~"),
+   KEY("KP_Enter",        "\r"),
+   
+   KEY(NULL, "END")
+};
+
+static const Keyout kps_keyout[] =
+{
+   KEY("KP_Left",         "\033Ot"),
+   KEY("KP_Right",        "\033Ov"),
+   KEY("KP_Up",           "\033Ox"),
+   KEY("KP_Down",         "\033Or"),
+   KEY("KP_Home",         "\033Ow"),
+   KEY("KP_End",          "\033Oq"),
+   KEY("KP_Prior",        "\033Oy"),
+   KEY("KP_Next",         "\033Os"),
+   KEY("KP_Insert",       "\033Op"),
+   KEY("KP_Delete",       "\033On"),
+   KEY("KP_Enter",        "\033OM"),
+   
+   KEY(NULL, "END")
+};
+
+static Eina_Bool
+_key_try(Termpty *ty, const Keyout *map, Evas_Event_Key_Down *ev)
+{
+   int i;
+   
+   if (!ev->keyname) return EINA_FALSE;
+   for (i = 0; map[i].in; i++)
+     {
+        if (!strcmp(ev->keyname, map[i].in))
+          {
+             termpty_write(ty, map[i].out, map[i].outlen);
+             return EINA_TRUE;
+          }
+     }
+   return EINA_FALSE;
+}
+
+void
+keyin_handle(Termpty *ty, Evas_Event_Key_Down *ev)
+{
+   if (ty->state.crlf)
+     {
+        if (_key_try(ty, crlf_keyout, ev)) return;
+     }
+   else
+     {
+        if (_key_try(ty, nocrlf_keyout, ev)) return;
+     }
+   if (ty->state.appcursor)
+     {
+        if (_key_try(ty, appcur_keyout, ev)) return;
+     }
+   if (_key_try(ty, keyout, ev)) return;
+   if (
+       ((ty->state.alt_kp) &&
+           (evas_key_modifier_is_set(ev->modifiers, "Shift"))) ||
+       ((!ty->state.alt_kp) &&
+           (!evas_key_modifier_is_set(ev->modifiers, "Shift"))))
+     {
+        if (_key_try(ty, kp_keyout, ev)) return;
+     }
+   else
+     {
+        if (_key_try(ty, kps_keyout, ev)) return;
+     }
+   if (evas_key_modifier_is_set(ev->modifiers, "Control"))
+     {
+        if (!strcmp(ev->keyname, "Minus"))
+          {
+             termpty_write(ty, "\037", 1); // generate US (unit separator)
+             return;
+          }
+        else if (!strcmp(ev->keyname, "space"))
+          {
+             termpty_write(ty, "\0", 1); // generate 0 byte for ctrl+space
+             return;
+          }
+     }
+   if (ev->string)
+     {
+        if ((ev->string[0]) && (!ev->string[1]))
+          {
+             if (evas_key_modifier_is_set(ev->modifiers, "Alt"))
+               termpty_write(ty, "\033", 1);
+          }
+        termpty_write(ty, ev->string, strlen(ev->string));
+     }
+}
diff --git a/src/bin/keyin.h b/src/bin/keyin.h
new file mode 100644 (file)
index 0000000..10174ca
--- /dev/null
@@ -0,0 +1,2 @@
+void keyin_handle(Termpty *ty, Evas_Event_Key_Down *ev);
+
diff --git a/src/bin/main.c b/src/bin/main.c
new file mode 100644 (file)
index 0000000..d6498f0
--- /dev/null
@@ -0,0 +1,95 @@
+#include <Elementary.h>
+#include "win.h"
+#include "termio.h"
+#include "config.h"
+
+const char *cmd = NULL;
+static Evas_Object *win, *bg, *term;
+
+static void
+_cb_focus_in(void *data, Evas_Object *obj, void *event)
+{
+   edje_object_signal_emit(bg, "focus,in", "terminology");
+   elm_object_focus_set(data, EINA_TRUE);
+}
+
+static void
+_cb_focus_out(void *data, Evas_Object *obj, void *event)
+{
+   edje_object_signal_emit(bg, "focus,out", "terminology");
+   elm_object_focus_set(data, EINA_FALSE);
+}
+
+static void
+_cb_size_hint(void *data, Evas *e, Evas_Object *obj, void *event)
+{
+   Evas_Coord mw, mh, rw, rh, w = 0, h = 0;
+   
+   evas_object_size_hint_min_get(obj, &mw, &mh);
+   evas_object_size_hint_request_get(obj, &rw, &rh);
+   
+   edje_object_size_min_calc(bg, &w, &h);
+   evas_object_size_hint_min_set(bg, w, h);
+   elm_win_size_base_set(win, w - mw, h - mh);
+   elm_win_size_step_set(win, mw, mh);
+   if (!evas_object_data_get(obj, "sizedone"))
+     {
+        evas_object_resize(win, w - mw + rw, h - mh + rh);
+        evas_object_data_set(obj, "sizedone", obj);
+     }
+}
+
+EAPI_MAIN int
+elm_main(int argc, char **argv)
+{
+   int i;
+   Evas_Object *o;
+   char buf[4096];
+
+   config_init();
+   elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED);
+   elm_app_compile_bin_dir_set(PACKAGE_BIN_DIR);
+   elm_app_compile_data_dir_set(PACKAGE_DATA_DIR);
+   elm_app_info_set(elm_main, "terminology", "themes/default.edj");
+
+   for (i = 1; i < argc; i++)
+     {
+        if ((!strcmp(argv[i], "-e")) && (i < (argc - 1)))
+          {
+             i++;
+             cmd = argv[i];
+          }
+     }
+   
+   win = tg_win_add();
+
+   bg = o = edje_object_add(evas_object_evas_get(win));
+   evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+   evas_object_size_hint_fill_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL);
+   snprintf(buf, sizeof(buf), "%s/themes/%s",
+            elm_app_data_dir_get(), config->theme);
+   edje_object_file_set(o, buf, "terminology/background");
+   elm_win_resize_object_add(win, o);
+   evas_object_show(o);
+   
+   term = o = termio_add(win, cmd, 80, 24);
+   termio_win_set(o, win);
+   evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+   evas_object_size_hint_fill_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL);
+   evas_object_event_callback_add(o, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
+                                  _cb_size_hint, win);
+   edje_object_part_swallow(bg, "terminology.content", o);
+   evas_object_show(o);
+
+   evas_object_smart_callback_add(win, "focus,in", _cb_focus_in, term);
+   evas_object_smart_callback_add(win, "focus,out", _cb_focus_out, term);
+   _cb_size_hint(win, evas_object_evas_get(win), term, NULL);
+   
+   evas_object_show(win);
+   
+   elm_run();
+   elm_shutdown();
+   config_shutdown();
+   return 0;
+}
+ELM_MAIN()
diff --git a/src/bin/termio.c b/src/bin/termio.c
new file mode 100644 (file)
index 0000000..300aba8
--- /dev/null
@@ -0,0 +1,1084 @@
+#include <Elementary.h>
+#include "termio.h"
+#include "termpty.h"
+#include "utf8.h"
+#include "col.h"
+#include "keyin.h"
+#include "config.h"
+
+typedef struct _Termio Termio;
+typedef struct _Termch Termch;
+
+struct _Termio
+{
+   Evas_Object_Smart_Clipped_Data __clipped_data;
+   struct {
+      int size;
+      const char *name;
+      int chw, chh;
+   } font;
+   struct {
+      int w, h;
+      Termch *array;
+   } grid;
+   struct {
+      Evas_Object *obj, *selo1, *selo2, *selo3;
+      int x, y;
+      struct {
+         int x, y;
+      } sel1, sel2;
+      Eina_Bool sel : 1;
+      Eina_Bool makesel : 1;
+   } cur;
+   int scroll;
+   Evas_Object *event;
+   Termpty *pty;
+   Ecore_Job *job;
+   Ecore_Timer *delayed_size_timer;
+   Evas_Object *win;
+   Eina_Bool jump_on_change : 1;
+};
+
+struct _Termch
+{
+   Evas_Object *bg;
+   Evas_Object *tx;
+};
+
+static Evas_Smart *_smart = NULL;
+static Evas_Smart_Class _termio_sc = EVAS_SMART_CLASS_INIT_NULL;
+
+static void _smart_calculate(Evas_Object *obj);
+
+static void
+_smart_apply(Evas_Object *obj)
+{
+   Termio *sd = evas_object_smart_data_get(obj);
+   Evas_Coord ox, oy, ow, oh;
+   char txt[8];
+   if (!sd) return;
+   evas_object_geometry_get(obj, &ox, &oy, &ow, &oh);
+   
+   if (sd->grid.array)
+     {
+        int i, j, x, y, w;
+        
+        i = 0;
+        for (y = 0; y < sd->grid.h; y++)
+          {
+             Termcell *cells;
+             
+             w = 0;
+             cells = termpty_cellrow_get(sd->pty, y - sd->scroll, &w);
+             j = 0;
+             for (x = 0; x < sd->grid.w; x++)
+               {
+                  Evas_Object *bg = sd->grid.array[i].bg;
+                  Evas_Object *tx = sd->grid.array[i].tx;
+                  
+                  if ((!cells) || (x >= w))
+                    {
+                       evas_object_hide(bg);
+                       evas_object_hide(tx);
+                    }
+                  else
+                    {
+                       Color c1, c2;
+                       
+                       if (cells[j].att.invisible)
+                         {
+                            evas_object_hide(tx);
+                            evas_object_hide(bg);
+                         }
+                       else
+                         {
+                            int cbd, cbdbg, cfg, cbg;
+                            
+                            // colors
+                            cbd = cells[j].att.bold;
+                            cbdbg = 0;
+                            cfg = cells[j].att.fg;
+                            cbg = cells[j].att.bg;
+                            
+                            if (cells[j].att.inverse)
+                              {
+                                 cfg = COL_INVERSE;
+                                 cbg = COL_INVERSEBG;
+                                 cbdbg = cbd;
+                                 c1 = colors[cbd][cfg];
+                                 c2 = colors[cbdbg][cbg];
+                                 if (cbg == COL_DEF) evas_object_hide(bg);
+                                 else evas_object_show(bg);
+                              }
+                            else
+                              {
+                                 if (cells[j].att.fg256)
+                                   c1 = colors256[cfg];
+                                 else
+                                   c1 = colors[cbd][cfg];
+                                 if (cells[j].att.bg256)
+                                   {
+                                      c2 = colors256[cbg];
+                                      evas_object_show(bg);
+                                   }
+                                 else
+                                   {
+                                      c2 = colors[cbdbg][cbg];
+                                      if (cbg == COL_DEF) evas_object_hide(bg);
+                                      else evas_object_show(bg);
+                                   }
+                              }
+                            if (cells[j].att.faint)
+                              {
+                                 c1.r /= 2;
+                                 c1.g /= 2;
+                                 c1.b /= 2;
+                                 c1.a /= 2;
+
+                                 c2.r /= 2;
+                                 c2.g /= 2;
+                                 c2.b /= 2;
+                                 c2.a /= 2;
+                              }
+//                            if (cells[j].att.unerline) {}
+//                            if (cells[j].att.italic) {} // never going 2 support
+//                            if (cells[j].att.strike) {}
+//                            if (cells[j].att.blink) {}
+//                            if (cells[j].att.blink2) {}
+                            evas_object_color_set(tx, c1.r, c1.g, c1.b, c1.a);
+                            evas_object_color_set(bg, c2.r, c2.g, c2.b, c2.a);
+                            
+                            // text - convert glyph back to utf8 str seq
+                            if (cells[j].glyph > 0)
+                              {
+                                 int g = cells[j].glyph;
+                                 
+                                 glyph_to_utf8(g, txt);
+                                 // special case for whitespace :)
+                                 if (cells[j].glyph == ' ')
+                                   {
+                                      evas_object_hide(tx);
+                                   }
+                                 else
+                                   {
+                                      evas_object_text_text_set(tx, txt);
+                                      evas_object_show(tx);
+                                   }
+                              }
+                            else
+                              {
+                                 evas_object_hide(tx);
+                                 if (cbg == COL_DEF) evas_object_hide(bg);
+                                 else evas_object_show(bg);
+                              }
+                         }
+                    }
+                  j++;
+                  i++;
+               }
+          }
+     }
+   if ((sd->scroll != 0) || (sd->pty->state.hidecursor))
+     evas_object_hide(sd->cur.obj);
+   else
+     evas_object_show(sd->cur.obj);
+   sd->cur.x = sd->pty->state.cx;
+   sd->cur.y = sd->pty->state.cy;
+   evas_object_move(sd->cur.obj, 
+                    ox + (sd->cur.x * sd->font.chw),
+                    oy + (sd->cur.y * sd->font.chh));
+   if (sd->cur.sel)
+     {
+        int x1, y1, x2, y2;
+        
+        x1 = sd->cur.sel1.x;
+        y1 = sd->cur.sel1.y;
+        x2 = sd->cur.sel2.x;
+        y2 = sd->cur.sel2.y;
+        if ((y1 > y2) || ((y1 == y2) && (x2 < x1)))
+          {
+             int t;
+             
+             t = x1; x1 = x2; x2 = t;
+             t = y1; y1 = y2; y2 = t;
+          }
+        
+        if (y2 > y1)
+          {
+             evas_object_move(sd->cur.selo1,
+                              ox + (x1 * sd->font.chw),
+                              oy + ((y1 + sd->scroll) * sd->font.chh));
+             evas_object_resize(sd->cur.selo1,
+                                (sd->grid.w - x1) * sd->font.chw,
+                                sd->font.chh);
+             evas_object_show(sd->cur.selo1);
+             
+             evas_object_move(sd->cur.selo3,
+                              ox, oy + ((y2 + sd->scroll) * sd->font.chh));
+             evas_object_resize(sd->cur.selo3,
+                                (x2 + 1) * sd->font.chw,
+                                sd->font.chh);
+             evas_object_show(sd->cur.selo3);
+          }
+        else
+          {
+             evas_object_move(sd->cur.selo1,
+                              ox + (x1 * sd->font.chw),
+                              oy + ((y1 + sd->scroll) * sd->font.chh));
+             evas_object_resize(sd->cur.selo1,
+                                (x2 - x1 + 1) * sd->font.chw,
+                                sd->font.chh);
+             evas_object_show(sd->cur.selo1);
+             evas_object_hide(sd->cur.selo3);
+          }
+        if (y2 > (y1 + 1))
+          {
+             evas_object_move(sd->cur.selo2,
+                              ox, oy + ((y1 + 1 + sd->scroll) * sd->font.chh));
+             evas_object_resize(sd->cur.selo2,
+                                sd->grid.w * sd->font.chw,
+                                (y2 - y1 - 1) * sd->font.chh);
+             evas_object_show(sd->cur.selo2);
+          }
+        else
+          evas_object_hide(sd->cur.selo2);
+     }
+   else
+     {
+        evas_object_hide(sd->cur.selo1);
+        evas_object_hide(sd->cur.selo2);
+        evas_object_hide(sd->cur.selo3);
+     }
+}
+
+static void
+_smart_size(Evas_Object *obj, int w, int h)
+{
+   Termio *sd = evas_object_smart_data_get(obj);
+   if (!sd) return;
+
+   if (w < 1) w = 1;
+   if (h < 1) h = 1;
+   if ((w == sd->grid.w) && (h == sd->grid.h)) return;
+
+   evas_event_freeze(evas_object_evas_get(obj));
+   if (sd->grid.array)
+     {
+        int i, size = sd->grid.w * sd->grid.h;
+
+        for (i = 0; i < size; i++)
+          {
+             if (sd->grid.array[i].bg) evas_object_del(sd->grid.array[i].bg);
+             if (sd->grid.array[i].tx) evas_object_del(sd->grid.array[i].tx);
+          }
+        free(sd->grid.array);
+        sd->grid.array = NULL;
+     }
+   sd->grid.w = w;
+   sd->grid.h = h;
+   sd->grid.array = calloc(1, sizeof(Termch) * sd->grid.w * sd->grid.h);
+   if (sd->grid.array)
+     {
+        int i, x, y;
+        
+        i = 0;
+        for (y = 0; y < sd->grid.h; y++)
+          {
+             for (x = 0; x < sd->grid.w; x++)
+               {
+                  Evas_Object *bg, *tx;
+                  
+                  bg = evas_object_rectangle_add(evas_object_evas_get(obj));
+                  tx = evas_object_text_add(evas_object_evas_get(obj));
+                  evas_object_pass_events_set(bg, EINA_TRUE);
+                  evas_object_pass_events_set(tx, EINA_TRUE);
+                  evas_object_propagate_events_set(bg, EINA_FALSE);
+                  evas_object_propagate_events_set(tx, EINA_FALSE);
+                  sd->grid.array[i].bg = bg;
+                  sd->grid.array[i].tx = tx;
+                  evas_object_smart_member_add(bg, obj);
+                  evas_object_smart_member_add(tx, obj);
+                  evas_object_resize(bg, sd->font.chw, sd->font.chh);
+                  evas_object_text_font_set(tx, sd->font.name, sd->font.size);
+                  evas_object_color_set(tx, 0, 0, 0, 0);
+                  evas_object_color_set(bg, 0, 0, 0, 0);
+                  i++;
+                }
+          }
+     }
+   evas_object_raise(sd->cur.selo1);
+   evas_object_raise(sd->cur.selo2);
+   evas_object_raise(sd->cur.selo3);
+   evas_object_raise(sd->cur.obj);
+   evas_object_resize(sd->cur.obj, sd->font.chw, sd->font.chh);
+   evas_object_size_hint_min_set(obj, sd->font.chw, sd->font.chh);
+   evas_object_size_hint_request_set(obj, 
+                                     sd->font.chw * sd->grid.w,
+                                     sd->font.chh * sd->grid.h);
+   evas_object_raise(sd->event);
+   termpty_resize(sd->pty, w, h);
+   _smart_calculate(obj);
+   _smart_apply(obj);
+   evas_event_thaw(evas_object_evas_get(obj));
+}
+
+static Eina_Bool
+_smart_cb_delayed_size(void *data)
+{
+   Evas_Object *obj = data;
+   Termio *sd = evas_object_smart_data_get(obj);
+   Evas_Coord ow = 0, oh = 0;
+   int w, h;
+   
+   if (!sd) return EINA_FALSE;
+   sd->delayed_size_timer = NULL;
+
+   evas_object_geometry_get(obj, NULL, NULL, &ow, &oh);
+   
+   w = ow / sd->font.chw;
+   h = oh / sd->font.chh;
+   _smart_size(obj, w, h);
+   return EINA_FALSE;
+}
+
+static void
+_smart_cb_change(void *data)
+{
+   Evas_Object *obj = data;
+   Termio *sd;
+   sd = evas_object_smart_data_get(obj);
+   if (!sd) return;
+   sd->job = NULL;
+   _smart_apply(obj);
+}
+
+static void
+_take_selection(Evas_Object *obj)
+{
+   Termio *sd = evas_object_smart_data_get(obj);
+   int x1, y1, x2, y2;
+   char *s;
+   
+   if (!sd) return;
+   x1 = sd->cur.sel1.x;
+   y1 = sd->cur.sel1.y;
+   x2 = sd->cur.sel2.x;
+   y2 = sd->cur.sel2.y;
+   if ((y1 > y2) || ((y1 == y2) && (x2 < x1)))
+     {
+        int t;
+        
+        t = x1; x1 = x2; x2 = t;
+        t = y1; y1 = y2; y2 = t;
+     }
+   s = termio_selection_get(obj, x1, y1, x2, y2);
+   if (s)
+     {
+        if (sd->win)
+          elm_cnp_selection_set(sd->win, ELM_SEL_TYPE_PRIMARY,
+                                ELM_SEL_FORMAT_TEXT, s, strlen(s));
+        free(s);
+     }
+}
+
+static void
+_clear_selection(Evas_Object *obj)
+{
+   Termio *sd = evas_object_smart_data_get(obj);
+   if (!sd) return;
+   if (!sd->win) return;
+   elm_object_cnp_selection_clear(sd->win, ELM_SEL_TYPE_PRIMARY);
+}
+
+static Eina_Bool
+_getsel_cb(void *data, Evas_Object *obj, Elm_Selection_Data *ev)
+{
+   Termio *sd = evas_object_smart_data_get(data);
+   if (!sd) return EINA_FALSE;
+   
+   if (ev->format == ELM_SEL_FORMAT_TEXT)
+     {
+        if (ev->len > 0)
+          termpty_write(sd->pty, ev->data, ev->len - 1);
+     }
+   return EINA_TRUE;
+}
+
+static void
+_paste_selection(Evas_Object *obj)
+{
+   Termio *sd = evas_object_smart_data_get(obj);
+   if (!sd) return;
+   if (!sd->win) return;
+   elm_cnp_selection_get(sd->win, ELM_SEL_TYPE_PRIMARY, ELM_SEL_FORMAT_TEXT,
+                         _getsel_cb, obj);
+}
+
+void
+_smart_cb_key_down(void *data, Evas *e, Evas_Object *obj, void *event)
+{
+   Evas_Event_Key_Down *ev = event;
+   Termio *sd;
+
+   sd = evas_object_smart_data_get(data);
+   if (!sd) return;
+   if (evas_key_modifier_is_set(ev->modifiers, "Shift"))
+     {
+        if (ev->keyname)
+          {
+             int by = sd->grid.h - 2;
+             
+             if (by < 1) by = 1;
+             if (!strcmp(ev->keyname, "Prior"))
+               {
+                  sd->scroll += by;
+                  if (sd->scroll > sd->pty->backscroll_num)
+                    sd->scroll = sd->pty->backscroll_num;
+                  if (sd->job) ecore_job_del(sd->job);
+                  sd->job = ecore_job_add(_smart_cb_change, obj);
+                  return;
+               }
+             else if (!strcmp(ev->keyname, "Next"))
+               {
+                  sd->scroll -= by;
+                  if (sd->scroll < 0) sd->scroll = 0;
+                  if (sd->job) ecore_job_del(sd->job);
+                  sd->job = ecore_job_add(_smart_cb_change, obj);
+                  return;
+               }
+             else if (!strcmp(ev->keyname, "Insert"))
+               {
+                  _paste_selection(data);
+                  return;
+               }
+          }
+     }
+   keyin_handle(sd->pty, ev);
+}
+
+void
+_smart_cb_focus_in(void *data, Evas *e, Evas_Object *obj, void *event)
+{
+   Termio *sd;
+
+   sd = evas_object_smart_data_get(data);
+   if (!sd) return;
+   edje_object_signal_emit(sd->cur.obj, "focus,in", "terminology");
+   if (!sd->win) return;
+   elm_win_keyboard_mode_set(sd->win, ELM_WIN_KEYBOARD_TERMINAL);
+}
+
+void
+_smart_cb_focus_out(void *data, Evas *e, Evas_Object *obj, void *event)
+{
+   Termio *sd;
+
+   sd = evas_object_smart_data_get(data);
+   if (!sd) return;
+   edje_object_signal_emit(sd->cur.obj, "focus,out", "terminology");
+   if (!sd->win) return;
+   elm_win_keyboard_mode_set(sd->win, ELM_WIN_KEYBOARD_OFF);
+}
+
+static void
+_smart_xy_to_cursor(Evas_Object *obj, Evas_Coord x, Evas_Coord y, int *cx, int *cy)
+{
+   Termio *sd;
+   Evas_Coord ox, oy;
+   
+   sd = evas_object_smart_data_get(obj);
+   if (!sd)
+     {
+        *cx = 0;
+        *cy = 0;
+        return;
+     }
+   evas_object_geometry_get(obj, &ox, &oy, NULL, NULL);
+   *cx = (x - ox) / sd->font.chw;
+   *cy = (y - oy) / sd->font.chh;
+   if (*cx < 0) *cx = 0;
+   else if (*cx >= sd->grid.w) *cx = sd->grid.w - 1;
+   if (*cy < 0) *cy = 0;
+   else if (*cy >= sd->grid.h) *cy = sd->grid.h - 1;
+}
+
+static void
+_sel_line(Evas_Object *obj, int cx, int cy)
+{
+   Termio *sd = evas_object_smart_data_get(obj);
+   if (!sd) return;
+
+   sd->cur.sel = 1;
+   sd->cur.makesel = 0;
+   sd->cur.sel1.x = 0;
+   sd->cur.sel1.y = cy;
+   sd->cur.sel2.x = sd->grid.w - 1;
+   sd->cur.sel2.y = cy;
+}
+
+static Eina_Bool
+_glyph_is_wordsep(int g)
+{
+   int i;
+
+   if (g == 0) return EINA_TRUE;
+   if (!config->wordsep) return EINA_FALSE;
+   for (i = 0;;)
+     {
+        int g2 = 0;
+
+        if (!config->wordsep[i]) break;
+        i = evas_string_char_next_get(config->wordsep, i, &g2);
+        if (i < 0) break;
+        if (g == g2) return EINA_TRUE;
+     }
+   return EINA_FALSE;
+}
+
+static void
+_sel_word(Evas_Object *obj, int cx, int cy)
+{
+   Termio *sd = evas_object_smart_data_get(obj);
+   Termcell *cells;
+   int x, w = 0;
+   if (!sd) return;
+
+   cells = termpty_cellrow_get(sd->pty, cy - sd->scroll, &w);
+   if (!cells) return;
+   sd->cur.sel = 1;
+   sd->cur.makesel = 0;
+   sd->cur.sel1.x = cx;
+   sd->cur.sel1.y = cy;
+   for (x = sd->cur.sel1.x; x >= 0; x--)
+     {
+        if (x >= w) break;
+        if (_glyph_is_wordsep(cells[x].glyph)) break;
+        sd->cur.sel1.x = x;
+     }
+   sd->cur.sel2.x = cx;
+   sd->cur.sel2.y = cy;
+   for (x = sd->cur.sel2.x; x < sd->grid.w; x++)
+     {
+        if (x >= w) break;
+        if (_glyph_is_wordsep(cells[x].glyph)) break;
+        sd->cur.sel2.x = x;
+     }
+}
+
+static void
+_smart_cb_mouse_down(void *data, Evas *e, Evas_Object *obj, void *event)
+{
+   Evas_Event_Mouse_Down *ev = event;
+   Termio *sd;
+   int cx, cy;
+
+   sd = evas_object_smart_data_get(data);
+   if (!sd) return;
+   _smart_xy_to_cursor(data, ev->canvas.x, ev->canvas.y, &cx, &cy);
+   if (ev->button == 1)
+     {
+        if (ev->flags & EVAS_BUTTON_TRIPLE_CLICK)
+          {
+             _sel_line(data, cx, cy - sd->scroll);
+             if (sd->cur.sel) _take_selection(data);
+          }
+        else if (ev->flags & EVAS_BUTTON_DOUBLE_CLICK)
+          {
+             _sel_word(data, cx, cy - sd->scroll);
+             if (sd->cur.sel) _take_selection(data);
+          }
+        else
+          {
+             if (sd->cur.sel)
+               {
+                  sd->cur.sel = 0;
+                  _clear_selection(data);
+               }
+             sd->cur.makesel = 1;
+             sd->cur.sel1.x = cx;
+             sd->cur.sel1.y = cy - sd->scroll;
+             sd->cur.sel2.x = cx;
+             sd->cur.sel2.y = cy - sd->scroll;
+          }
+        if (sd->job) ecore_job_del(sd->job);
+        sd->job = ecore_job_add(_smart_cb_change, data);
+     }
+   else if (ev->button == 2)
+     _paste_selection(data);
+   else if (ev->button == 3)
+     {
+        // XXX: popup config panel
+     }
+}
+
+static void
+_smart_cb_mouse_up(void *data, Evas *e, Evas_Object *obj, void *event)
+{
+   Evas_Event_Mouse_Up *ev = event;
+   Termio *sd;
+   int cx, cy;
+
+   sd = evas_object_smart_data_get(data);
+   if (!sd) return;
+   _smart_xy_to_cursor(data, ev->canvas.x, ev->canvas.y, &cx, &cy);
+   if (sd->cur.makesel)
+     {
+        sd->cur.makesel = 0;
+        if (sd->cur.sel)
+          {
+             sd->cur.sel2.x = cx;
+             sd->cur.sel2.y = cy - sd->scroll;
+             if (sd->job) ecore_job_del(sd->job);
+             sd->job = ecore_job_add(_smart_cb_change, data);
+             _take_selection(data);
+          }
+     }
+}
+
+static void
+_smart_cb_mouse_move(void *data, Evas *e, Evas_Object *obj, void *event)
+{
+   Evas_Event_Mouse_Move *ev = event;
+   Termio *sd;
+   int cx, cy;
+
+   sd = evas_object_smart_data_get(data);
+   if (!sd) return;
+   _smart_xy_to_cursor(data, ev->cur.canvas.x, ev->cur.canvas.y, &cx, &cy);
+   if (sd->cur.makesel)
+     {
+        if (!sd->cur.sel)
+          {
+             if ((cx != sd->cur.sel1.x) ||
+                 ((cy - sd->scroll) != sd->cur.sel1.y))
+               sd->cur.sel = 1;
+          }
+        sd->cur.sel2.x = cx;
+        sd->cur.sel2.y = cy - sd->scroll;
+        if (sd->job) ecore_job_del(sd->job);
+        sd->job = ecore_job_add(_smart_cb_change, data);
+     }
+}
+
+static void
+_smart_cb_mouse_wheel(void *data, Evas *e, Evas_Object *obj, void *event)
+{
+   Evas_Event_Mouse_Wheel *ev = event;
+   Termio *sd;
+
+   sd = evas_object_smart_data_get(data);
+   if (!sd) return;
+   if (sd->pty->altbuf) return;
+   sd->scroll -= (ev->z * 4);
+   if (sd->scroll > sd->pty->backscroll_num)
+     sd->scroll = sd->pty->backscroll_num;
+   else if (sd->scroll < 0) sd->scroll = 0;
+   if (sd->job) ecore_job_del(sd->job);
+   sd->job = ecore_job_add(_smart_cb_change, data);
+}
+
+static void
+_smart_add(Evas_Object *obj)
+{
+   Termio *sd;
+   Evas_Object_Smart_Clipped_Data *cd;
+   _termio_sc.add(obj);
+   cd = evas_object_smart_data_get(obj);
+   if (!cd) return;
+   sd = calloc(1, sizeof(Termio));
+   if (!sd) return;
+   sd->__clipped_data = *cd;
+   free(cd);
+   evas_object_smart_data_set(obj, sd);
+
+   sd->jump_on_change = config->jump_on_change;
+   
+     {
+        Evas_Object *o;
+        Evas_Coord w = 2, h = 2;
+        char buf[4096];
+
+        if (config->font.bitmap)
+          {
+             snprintf(buf, sizeof(buf), "%s/fonts/%s",
+                      elm_app_data_dir_get(), config->font.name);
+             sd->font.name = eina_stringshare_add(buf);
+          }
+        else
+          sd->font.name = eina_stringshare_add(config->font.name);
+        sd->font.size = config->font.size;
+        o = evas_object_text_add(evas_object_evas_get(obj));
+        evas_object_text_font_set(o, sd->font.name, sd->font.size);
+        evas_object_text_text_set(o, "X");
+        evas_object_geometry_get(o, NULL, NULL, &w, &h);
+        evas_object_del(o);
+        if (w < 1) w = 1;
+        if (h < 1) h = 1;
+        sd->font.chw = w;
+        sd->font.chh = h;
+        
+        o = evas_object_rectangle_add(evas_object_evas_get(obj));
+        evas_object_pass_events_set(o, EINA_TRUE);
+        evas_object_propagate_events_set(o, EINA_FALSE);
+        evas_object_smart_member_add(o, obj);
+        sd->cur.selo1 = o;
+        evas_object_color_set(o, 64, 64, 64, 64);
+        o = evas_object_rectangle_add(evas_object_evas_get(obj));
+        evas_object_pass_events_set(o, EINA_TRUE);
+        evas_object_propagate_events_set(o, EINA_FALSE);
+        evas_object_smart_member_add(o, obj);
+        sd->cur.selo2 = o;
+        evas_object_color_set(o, 64, 64, 64, 64);
+        o = evas_object_rectangle_add(evas_object_evas_get(obj));
+        evas_object_pass_events_set(o, EINA_TRUE);
+        evas_object_propagate_events_set(o, EINA_FALSE);
+        evas_object_smart_member_add(o, obj);
+        sd->cur.selo3 = o;
+        evas_object_color_set(o, 64, 64, 64, 64);
+        
+        o = edje_object_add(evas_object_evas_get(obj));
+        evas_object_pass_events_set(o, EINA_TRUE);
+        evas_object_propagate_events_set(o, EINA_FALSE);
+        evas_object_smart_member_add(o, obj);
+        sd->cur.obj = o;
+        snprintf(buf, sizeof(buf), "%s/themes/%s",
+                 elm_app_data_dir_get(), config->theme);
+        edje_object_file_set(o, buf, "terminology/cursor");
+        evas_object_resize(o, sd->font.chw, sd->font.chh);
+        evas_object_show(o);
+
+        o = evas_object_rectangle_add(evas_object_evas_get(obj));
+        evas_object_smart_member_add(o, obj);
+        sd->event = o;
+        evas_object_color_set(o, 0, 0, 0, 0);
+        evas_object_show(o);
+        
+        evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_DOWN,
+                                       _smart_cb_mouse_down, obj);
+        evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_UP,
+                                       _smart_cb_mouse_up, obj);
+        evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_MOVE,
+                                       _smart_cb_mouse_move, obj);
+        evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_WHEEL,
+                                       _smart_cb_mouse_wheel, obj);
+     }
+
+   evas_object_event_callback_add(obj, EVAS_CALLBACK_KEY_DOWN,
+                                  _smart_cb_key_down, obj);
+   evas_object_event_callback_add(obj, EVAS_CALLBACK_FOCUS_IN,
+                                  _smart_cb_focus_in, obj);
+   evas_object_event_callback_add(obj, EVAS_CALLBACK_FOCUS_OUT,
+                                  _smart_cb_focus_out, obj);
+}
+
+static void
+_smart_del(Evas_Object *obj)
+{
+   Termio *sd = evas_object_smart_data_get(obj);
+   if (!sd) return;
+   if (sd->cur.obj) evas_object_del(sd->cur.obj);
+   if (sd->event) evas_object_del(sd->event);
+   if (sd->cur.selo1) evas_object_del(sd->cur.selo1);
+   if (sd->cur.selo2) evas_object_del(sd->cur.selo2);
+   if (sd->cur.selo3) evas_object_del(sd->cur.selo3);
+   if (sd->job) ecore_job_del(sd->job);
+   if (sd->delayed_size_timer) ecore_timer_del(sd->delayed_size_timer);
+   if (sd->grid.array) free(sd->grid.array);
+   if (sd->font.name) eina_stringshare_del(sd->font.name);
+   if (sd->pty) termpty_free(sd->pty);
+   sd->cur.obj = NULL;
+   sd->event = NULL;
+   sd->cur.selo1 = NULL;
+   sd->cur.selo2 = NULL;
+   sd->cur.selo3 = NULL;
+   sd->job = NULL;
+   sd->delayed_size_timer = NULL;
+   sd->grid.array = NULL;
+   sd->font.name = NULL;
+   sd->pty = NULL;
+   _termio_sc.del(obj);
+   evas_object_smart_data_set(obj, NULL);
+}
+
+static void
+_smart_resize(Evas_Object *obj, Evas_Coord w, Evas_Coord h)
+{
+   Termio *sd = evas_object_smart_data_get(obj);
+   Evas_Coord ow, oh;
+   if (!sd) return;
+   evas_object_geometry_get(obj, NULL, NULL, &ow, &oh);
+   if ((ow == w) && (oh == h)) return;
+   evas_object_smart_changed(obj);
+   if (sd->delayed_size_timer) ecore_timer_del(sd->delayed_size_timer);
+   sd->delayed_size_timer = ecore_timer_add(0.02, _smart_cb_delayed_size, obj);
+   evas_object_resize(sd->event, ow, oh);
+}
+
+static void
+_smart_calculate(Evas_Object *obj)
+{
+   Termio *sd = evas_object_smart_data_get(obj);
+   Evas_Coord ox, oy, ow, oh;
+   
+   if (!sd) return;
+
+   evas_object_geometry_get(obj, &ox, &oy, &ow, &oh);
+   if (sd->grid.array)
+     {
+        int i, x, y;
+        
+        i = 0;
+        for (y = 0; y < sd->grid.h; y++)
+          {
+             for (x = 0; x < sd->grid.w; x++)
+               {
+                  evas_object_move(sd->grid.array[i].bg,
+                                   ox + (x * sd->font.chw),
+                                   oy + (y * sd->font.chh));
+                  evas_object_move(sd->grid.array[i].tx,
+                                   ox + (x * sd->font.chw),
+                                   oy + (y * sd->font.chh));
+                  i++;
+               }
+          }
+     }
+   evas_object_move(sd->cur.obj, 
+                    ox + (sd->cur.x * sd->font.chw),
+                    oy + (sd->cur.y * sd->font.chh));
+   evas_object_move(sd->event, ox, oy);
+   evas_object_resize(sd->event, ow, oh);
+}
+
+static void
+_smart_move(Evas_Object *obj, Evas_Coord x, Evas_Coord y)
+{  
+   Termio *sd = evas_object_smart_data_get(obj);
+   if (!sd) return;
+   evas_object_smart_changed(obj);
+}
+
+static void
+_smart_init(void)
+{
+   static Evas_Smart_Class sc;
+   
+   evas_object_smart_clipped_smart_set(&_termio_sc);
+   sc           = _termio_sc;
+   sc.name      = "termio";
+   sc.version   = EVAS_SMART_CLASS_VERSION;
+   sc.add       = _smart_add;
+   sc.del       = _smart_del;
+   sc.resize    = _smart_resize;
+   sc.move      = _smart_move;
+   sc.calculate = _smart_calculate;
+   _smart = evas_smart_class_new(&sc);
+}
+
+static void
+_smart_pty_change(void *data)
+{
+   Evas_Object *obj = data;
+   Termio *sd;
+   sd = evas_object_smart_data_get(obj);
+   if (!sd) return;
+
+   if (sd->jump_on_change) // if scroll to bottom on updates
+     {
+        // if term changed = croll back to bottom
+        sd->scroll = 0;
+     }
+   if (sd->job) ecore_job_del(sd->job);
+   sd->job = ecore_job_add(_smart_cb_change, obj);
+}
+
+static void
+_smart_pty_scroll(void *data)
+{
+   Evas_Object *obj = data;
+   Termio *sd;
+   int changed = 0;
+   sd = evas_object_smart_data_get(obj);
+   if (!sd) return;
+
+   if ((!sd->jump_on_change) && // if NOT scroll to bottom on updates
+       (sd->scroll > 0)) 
+     {
+        // adjust scroll position for added scrollback
+        sd->scroll++;
+        if (sd->scroll > sd->pty->backscroll_num)
+          sd->scroll = sd->pty->backscroll_num;
+        changed = 1;
+     }
+   if (sd->cur.sel)
+     {
+        sd->cur.sel1.y--;
+        sd->cur.sel2.y--;
+        changed = 1;
+     }
+   if (changed)
+     {
+        if (sd->job) ecore_job_del(sd->job);
+        sd->job = ecore_job_add(_smart_cb_change, obj);
+     }
+}
+
+static void
+_smart_pty_title(void *data)
+{
+   Evas_Object *obj = data;
+   Termio *sd;
+   sd = evas_object_smart_data_get(obj);
+   if (!sd) return;
+   if (!sd->win) return;
+   elm_win_title_set(sd->win, sd->pty->prop.title);
+}
+
+static void
+_smart_pty_icon(void *data)
+{
+   Evas_Object *obj = data;
+   Termio *sd;
+   sd = evas_object_smart_data_get(obj);
+   if (!sd) return;
+   if (!sd->win) return;
+   elm_win_icon_name_set(sd->win, sd->pty->prop.icon);
+}
+
+static void
+_smart_pty_cancel_sel(void *data)
+{
+   Evas_Object *obj = data;
+   Termio *sd;
+   sd = evas_object_smart_data_get(obj);
+   if (!sd) return;
+   if (sd->cur.sel)
+     {
+        sd->cur.sel = 0;
+        _clear_selection(data);
+        sd->cur.makesel = 0;
+        if (sd->job) ecore_job_del(sd->job);
+        sd->job = ecore_job_add(_smart_cb_change, data);
+     }
+}
+
+Evas_Object *
+termio_add(Evas_Object *parent, const char *cmd, int w, int h)
+{
+   Evas *e;
+   Evas_Object *obj;
+   Termio *sd;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
+   e = evas_object_evas_get(parent);
+   if (!e) return NULL;
+   
+   if (!_smart) _smart_init();
+   obj = evas_object_smart_add(e, _smart);
+   sd = evas_object_smart_data_get(obj);
+   if (!sd) return obj;
+   sd->pty = termpty_new(cmd, w, h, config->scrollback);
+   sd->pty->cb.change.func = _smart_pty_change;
+   sd->pty->cb.change.data = obj;
+   sd->pty->cb.scroll.func = _smart_pty_scroll;
+   sd->pty->cb.scroll.data = obj;
+   sd->pty->cb.set_title.func = _smart_pty_title;
+   sd->pty->cb.set_title.data = obj;
+   sd->pty->cb.set_icon.func = _smart_pty_icon;
+   sd->pty->cb.set_icon.data = obj;
+   sd->pty->cb.cancel_sel.func = _smart_pty_cancel_sel;
+   sd->pty->cb.cancel_sel.data = obj;
+   _smart_size(obj, w, h);
+   return obj;
+}
+
+void
+termio_win_set(Evas_Object *obj, Evas_Object *win)
+{
+   Termio *sd;
+   sd = evas_object_smart_data_get(obj);
+   if (!sd) return;
+   sd->win = win;
+}
+
+char *
+termio_selection_get(Evas_Object *obj, int c1x, int c1y, int c2x, int c2y)
+{
+   Termio *sd;
+   sd = evas_object_smart_data_get(obj);
+   Eina_Strbuf *sb;
+   char *s, txt[8];
+   int x, y;
+   
+   if (!sd) return NULL;
+   sb = eina_strbuf_new();
+   for (y = c1y; y <= c2y; y++)
+     {
+        Termcell *cells;
+        int w, last0, v, x1, x2;
+        
+        w = 0;
+        last0 = -1;
+        cells = termpty_cellrow_get(sd->pty, y - sd->scroll, &w);
+        if (w > sd->grid.w) w = sd->grid.w;
+        x1 = c1x;
+        x2 = c2x;
+        if (c1y != c2y)
+          {
+             if (y == c1y) x2 = w - 1;
+             else if (y == c2y) x1 = 0;
+             else
+               {
+                  x1 = 0;
+                  x2 = w - 1;
+               }
+          }
+        for (x = x1; x <= x2; x++)
+          {
+             if (x >= w) break;
+             if (cells[x].glyph == 0)
+               {
+                  if (last0 < 0) last0 = x;
+               }
+             else if (cells[x].att.newline)
+               {
+                  last0 = -1;
+                  eina_strbuf_append(sb, "\n");
+                  break;
+               }
+             else if (cells[x].att.tab)
+               {
+                  eina_strbuf_append(sb, "\t");
+                  x = ((x + 8) / 8) * 8;
+                  x--;
+               }
+             else
+               {
+                  if (last0 >= 0)
+                    {
+                       v = x - last0 - 1;
+                       last0 = -1;
+                       while (v >= 0)
+                         {
+                            eina_strbuf_append(sb, " ");
+                            v--;
+                         }
+                       if (x == (w - 1))
+                         {
+                            if (!cells[x].att.autowrapped)
+                              eina_strbuf_append(sb, "\n");
+                         }
+                    }
+                  glyph_to_utf8(cells[x].glyph, txt);
+                  eina_strbuf_append(sb, txt);
+               }
+          }
+        if (last0 >= 0)
+          {
+             eina_strbuf_append(sb, "\n");
+          }
+     }
+   
+   s = eina_strbuf_string_steal(sb);
+   eina_strbuf_free(sb);
+   return s;
+}
diff --git a/src/bin/termio.h b/src/bin/termio.h
new file mode 100644 (file)
index 0000000..333b36c
--- /dev/null
@@ -0,0 +1,3 @@
+Evas_Object *termio_add(Evas_Object *parent, const char *cmd, int w, int h);
+void         termio_win_set(Evas_Object *obj, Evas_Object *win);
+char        *termio_selection_get(Evas_Object *obj, int c1x, int c1y, int c2x, int c2y);
diff --git a/src/bin/termpty.c b/src/bin/termpty.c
new file mode 100644 (file)
index 0000000..8bf007c
--- /dev/null
@@ -0,0 +1,1574 @@
+#define _XOPEN_SOURCE 600
+#include <Elementary.h>
+#include "termpty.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+
+///////////////////////////////////////////////////////////////////////////
+//#define DBG(f, args...) printf(f, ##args)
+#define DBG(f, args...) do {} while (0)
+///////////////////////////////////////////////////////////////////////////
+//#define INF(f, args...) printf("==INF: "f, ##args)
+#define INF(f, args...) do {} while (0)
+///////////////////////////////////////////////////////////////////////////
+#define ERR(f, args...) printf("######ERR: "f, ##args)
+//#define ERR(f, args...) do {} while (0)
+
+static void
+_text_clear(Termpty *ty, Termcell *cells, int count, int val, Eina_Bool inherit_att)
+{
+   int i;
+   Termatt clear;
+   
+   memset(&clear, 0, sizeof(clear));
+   if (inherit_att)
+     {
+        for (i = 0; i < count; i++)
+          {
+             cells[i].glyph = val;
+             cells[i].att = ty->state.att;
+          }
+     }
+   else
+     {
+        for (i = 0; i < count; i++)
+          {
+             cells[i].glyph = val;
+             cells[i].att = clear;
+          }
+     }
+}
+
+static void
+_text_copy(Termpty *ty, Termcell *cells, Termcell *dest, int count)
+{
+   memcpy(dest, cells, sizeof(*(cells)) * count);
+}
+
+static void
+_text_save_top(Termpty *ty)
+{
+   Termsave *ts;
+   
+   ts = malloc(sizeof(Termsave) + ((ty->w - 1) * sizeof(Termcell)));
+   ts->w = ty->w;
+   _text_copy(ty, ty->screen, ts->cell, ty->w);
+   if (!ty->back) ty->back = calloc(1, sizeof(Termsave *) * ty->backmax);
+   if (ty->back[ty->backpos]) free(ty->back[ty->backpos]);
+   ty->back[ty->backpos] = ts;
+   ty->backpos++;
+   if (ty->backpos >= ty->backmax) ty->backpos = 0;
+   ty->backscroll_num++;
+   if (ty->backscroll_num >= ty->backmax) ty->backscroll_num = ty->backmax - 1;
+}
+
+static void
+_text_scroll(Termpty *ty)
+{
+   Termcell *cells = NULL, *cells2;
+   int y, y1 = 0, y2 = ty->h - 1;
+
+   if (ty->state.scroll_y2 != 0)
+     {
+        y1 = ty->state.scroll_y1;
+        y2 = ty->state.scroll_y2 - 1;
+     }
+   else
+     {
+        if (!ty->altbuf)
+          {
+             _text_save_top(ty);
+             if (ty->cb.scroll.func) ty->cb.scroll.func(ty->cb.scroll.data);
+          }
+        else
+          if (ty->cb.cancel_sel.func)
+            ty->cb.cancel_sel.func(ty->cb.cancel_sel.data);
+     }
+   DBG("... scroll!!!!! [%i->%i]\n", y1, y2);
+   cells2 = &(ty->screen[y2 * ty->w]);
+   for (y = y1; y < y2; y++)
+     {
+        cells = &(ty->screen[y * ty->w]);
+        cells2 = &(ty->screen[(y + 1) * ty->w]);
+        _text_copy(ty, cells2, cells, ty->w);
+     }
+   _text_clear(ty, cells2, ty->w, ' ', EINA_TRUE);
+}
+
+static void
+_text_scroll_rev(Termpty *ty)
+{
+   Termcell *cells, *cells2 = NULL;
+   int y, y1 = 0, y2 = ty->h - 1;
+
+   if (ty->state.scroll_y2 != 0)
+     {
+        y1 = ty->state.scroll_y1;
+        y2 = ty->state.scroll_y2 - 1;
+     }
+   DBG("... scroll rev!!!!! [%i->%i]\n", y1, y2);
+   cells = &(ty->screen[y2 * ty->w]);
+   for (y = y2; y > y1; y--)
+     {
+        cells = &(ty->screen[(y - 1) * ty->w]);
+        cells2 = &(ty->screen[y * ty->w]);
+        _text_copy(ty, cells, cells2, ty->w);
+     }
+   _text_clear(ty, cells, ty->w, ' ', EINA_TRUE);
+}
+
+static void
+_text_scroll_test(Termpty *ty)
+{
+   int e = ty->h;
+   
+   if (ty->state.scroll_y2 != 0) e = ty->state.scroll_y2;
+   if (ty->state.cy >= e)
+     {
+        _text_scroll(ty);
+        ty->state.cy = e - 1;
+     }
+}
+
+static void
+_text_scroll_rev_test(Termpty *ty)
+{
+   int b = 0;
+   
+   if (ty->state.scroll_y2 != 0) b = ty->state.scroll_y1;
+   if (ty->state.cy < b)
+     {
+        _text_scroll_rev(ty);
+        ty->state.cy = b;
+     }
+}
+
+static void
+_text_append(Termpty *ty, const int *glyphs, int len)
+{
+   Termcell *cells;
+   int i, j;
+
+   cells = &(ty->screen[ty->state.cy * ty->w]);
+   for (i = 0; i < len; i++)
+     {
+        if (ty->state.wrapnext)
+          {
+             cells[ty->state.cx].att.autowrapped = 1;
+             ty->state.wrapnext = 0;
+             ty->state.cx = 0;
+             ty->state.cy++;
+             _text_scroll_test(ty);
+             cells = &(ty->screen[ty->state.cy * ty->w]);
+          }
+        if (ty->state.insert)
+          {
+             for (j = ty->w - 1; j > ty->state.cx; j--)
+               cells[j] = cells[j - 1];
+          }
+        cells[ty->state.cx].glyph = glyphs[i];
+        cells[ty->state.cx].att = ty->state.att;
+        if (ty->state.wrap)
+          {
+             ty->state.wrapnext = 0;
+             if (ty->state.cx >= (ty->w - 1)) ty->state.wrapnext = 1;
+             else ty->state.cx++;
+          }
+        else
+          {
+             ty->state.wrapnext = 0;
+             ty->state.cx++;
+             if (ty->state.cx >= ty->w)
+               ty->state.cx = ty->w - 1;
+          }
+     }
+}
+
+static void
+_term_write(Termpty *ty, const char *txt, int size)
+{
+   if (write(ty->fd, txt, size) < 0) perror("write");
+}
+#define _term_txt_write(ty, txt) _term_write(ty, txt, sizeof(txt) - 1)
+
+#define CLR_END   0
+#define CLR_BEGIN 1
+#define CLR_ALL   2
+
+static void
+_clear_line(Termpty *ty, int mode, int limit)
+{
+   Termcell *cells;
+   int n = 0;
+
+   cells = &(ty->screen[ty->state.cy * ty->w]);
+   switch (mode)
+     {
+      case CLR_END:
+        n = ty->w - ty->state.cx;
+        cells = &(cells[ty->state.cx]);
+        break;
+      case CLR_BEGIN:
+        n = ty->state.cx + 1;
+        break;
+      case CLR_ALL:
+        n = ty->w;
+        break;
+      default:
+        return;
+     }
+   if (n > limit) n = limit;
+   _text_clear(ty, cells, n, 0, EINA_TRUE);
+}
+
+static void
+_clear_screen(Termpty *ty, int mode)
+{
+   Termcell *cells;
+           
+   cells = ty->screen;
+   switch (mode)
+     {
+      case CLR_END:
+        _clear_line(ty, mode, ty->w);
+        if (ty->state.cy < (ty->h - 1))
+          {
+             cells = &(ty->screen[(ty->state.cy + 1) * ty->w]);
+             _text_clear(ty, cells, ty->w * (ty->h - ty->state.cy - 1), 0, EINA_TRUE);
+          }
+        break;
+      case CLR_BEGIN:
+        if (ty->state.cy > 0)
+          _text_clear(ty, cells, ty->w * ty->state.cy, 0, EINA_TRUE);
+        _clear_line(ty, mode, ty->w);
+        break;
+      case CLR_ALL:
+        _text_clear(ty, cells, ty->w * ty->h, 0, EINA_TRUE);
+        break;
+      default:
+        break;
+     }
+   if (ty->cb.cancel_sel.func)
+     ty->cb.cancel_sel.func(ty->cb.cancel_sel.data);
+}
+
+static void
+_clear_all(Termpty *ty)
+{
+   if (!ty->screen) return;
+   memset(ty->screen, 0, sizeof(*(ty->screen)) * ty->w * ty->h);
+}
+
+static void
+_reset_att(Termatt *att)
+{
+   att->fg = COL_DEF;
+   att->bg = COL_DEF;
+   att->bold = 0;
+   att->faint = 0;
+   att->italic = 0;
+   att->underline = 0;
+   att->blink = 0;
+   att->blink2 = 0;
+   att->inverse = 0;
+   att->invisible = 0;
+   att->strike = 0;
+   att->fg256 = 0;
+   att->bg256 = 0;
+   att->autowrapped = 0;
+   att->newline = 0;
+   att->tab = 0;
+}
+
+static void
+_reset_state(Termpty *ty)
+{
+   ty->state.cx = 0;
+   ty->state.cy = 0;
+   ty->state.scroll_y1 = 0;
+   ty->state.scroll_y2 = 0;
+   ty->state.had_cr_x = 0;
+   ty->state.had_cr_y = 0;
+   _reset_att(&(ty->state.att));
+   ty->state.charset = 0;
+   ty->state.charsetch = 'B';
+   ty->state.chset[0] = 'B';
+   ty->state.chset[1] = 'B';
+   ty->state.chset[2] = 'B';
+   ty->state.chset[3] = 'B';
+   ty->state.multibyte = 0;
+   ty->state.alt_kp = 0;
+   ty->state.insert = 0;
+   ty->state.appcursor = 0;
+   ty->state.wrap = 1;
+   ty->state.wrapnext = 0;
+   ty->state.hidecursor = 0;
+   ty->state.crlf = 0;
+   ty->state.had_cr = 0;
+}
+
+static void
+_cursor_copy(Termstate *state, Termstate *dest)
+{
+   dest->cx = state->cx;
+   dest->cy = state->cy;
+}
+
+static int
+_csi_arg_get(char **ptr)
+{
+   char *b = *ptr;
+   int octal = 0;
+   int sum = 0;
+   
+   while ((*b) && (!isdigit(*b))) b++;
+   if (!*b)
+     {
+        *ptr = NULL;
+        return 0;
+     }
+   if (*b == '0') octal = 1;
+   while (isdigit(*b))
+     {
+        if (octal) sum *= 8;
+        else sum *= 10;
+        sum += *b - '0';
+        b++;
+     }
+   *ptr = b;
+   return sum;
+}
+
+static int
+_handle_esc_csi(Termpty *ty, const int *c, int *ce)
+{
+   int *cc, arg, first = 1, i;
+   char buf[4096], *b;
+   
+   cc = (int *)c;
+   b = buf;
+   while ((cc < ce) && (*cc >= '0') && (*cc <= '?'))
+     {
+        *b = *cc;
+        b++;
+        cc++;
+     }
+   // if cc == ce then we got to the end of the string with no end marker
+   // so return -2 to indicate to go back to the escape beginning when
+   // there is more bufer available
+   if (cc == ce) return -2;
+   *b = 0;
+   b = buf;
+   DBG(" CSI: '%c' args '%s'\n", *cc, buf);
+   switch (*cc)
+     {
+      case 'm': // color set
+        while (b)
+          {
+             arg = _csi_arg_get(&b);
+             if ((first) && (!b))
+               _reset_att(&(ty->state.att));
+             else if (b)
+               {
+                  first = 0;
+                  switch (arg)
+                    {
+                     case 0: // reset to normal
+                       _reset_att(&(ty->state.att));
+                       break;
+                     case 1: // bold/bright
+                       ty->state.att.bold = 1;
+                       break;
+                     case 2: // faint
+                       ty->state.att.faint = 1;
+                       break;
+                     case 3: // italic
+                       ty->state.att.italic = 1;
+                       break;
+                     case 4: // underline
+                       ty->state.att.underline = 1;
+                       break;
+                     case 5: // blink
+                       ty->state.att.blink = 1;
+                       break;
+                     case 6: // blink rapid
+                       ty->state.att.blink2 = 1;
+                       break;
+                     case 7: // reverse
+                       ty->state.att.inverse = 1;
+                       break;
+                     case 8: // invisible
+                       ty->state.att.invisible = 1;
+                       break;
+                     case 9: // strikethrough
+                       ty->state.att.strike = 1;
+                       break;
+                     case 21: // no bold/bright
+                       ty->state.att.bold = 0;
+                       break;
+                     case 22: // no faint
+                       ty->state.att.faint = 0;
+                       break;
+                     case 23: // no italic
+                       ty->state.att.italic = 0;
+                       break;
+                     case 24: // no underline
+                       ty->state.att.underline = 0;
+                       break;
+                     case 25: // no blink
+                       ty->state.att.blink = 0;
+                       ty->state.att.blink2 = 0;
+                       break;
+                     case 27: // no reverse
+                       ty->state.att.inverse = 0;
+                       break;
+                     case 28: // no invisible
+                       ty->state.att.invisible = 0;
+                       break;
+                     case 29: // no strikethrough
+                       ty->state.att.strike = 0;
+                       break;
+                     case 30: // fg
+                     case 31:
+                     case 32:
+                     case 33:
+                     case 34:
+                     case 35:
+                     case 36:
+                     case 37:
+                       ty->state.att.fg256 = 0;
+                       ty->state.att.fg = (arg - 30) + COL_BLACK;
+                       break;
+                     case 38: // xterm 256 fg color ???
+                       // now check if next arg is 5
+                       arg = _csi_arg_get(&b);
+                       if (arg != 5) ERR("Failed xterm 256 color fg esc 5\n");
+                       else
+                         {
+                            // then get next arg - should be color index 0-255
+                            arg = _csi_arg_get(&b);
+                            if (!b) ERR("Failed xterm 256 color fg esc val\n");
+                            else
+                              {
+                                 ty->state.att.fg256 = 1;
+                                 ty->state.att.fg = arg;
+                              }
+                         }
+                       break;
+                     case 39: // default fg color
+                       ty->state.att.fg256 = 0;
+                       ty->state.att.fg = COL_DEF;
+                       break;
+                     case 40: // bg
+                     case 41:
+                     case 42:
+                     case 43:
+                     case 44:
+                     case 45:
+                     case 46:
+                     case 47:
+                       ty->state.att.bg256 = 0;
+                       ty->state.att.bg = (arg - 40) + COL_BLACK;
+                       break;
+                     case 48: // xterm 256 bg color ???
+                       // now check if next arg is 5
+                       arg = _csi_arg_get(&b);
+                       if (arg != 5) ERR("Failed xterm 256 color bg esc 5\n");
+                       else
+                         {
+                            // then get next arg - should be color index 0-255
+                            arg = _csi_arg_get(&b);
+                            if (!b) ERR("Failed xterm 256 color bg esc val\n");
+                            else
+                              {
+                                 ty->state.att.bg256 = 1;
+                                 ty->state.att.bg = arg;
+                              }
+                         }
+                       break;
+                     case 49: // default bg color
+                       ty->state.att.bg256 = 0;
+                       ty->state.att.bg = COL_DEF;
+                       break;
+                     default: //  not handled???
+                       ERR("  color cmd [%i] not handled\n", arg);
+                       break;
+                    }
+               }
+          }
+        break;
+      case '@': // insert N blank chars
+        arg = _csi_arg_get(&b);
+        if (arg < 1) arg = 1;
+          {
+             int pi = ty->state.insert;
+             int blank[1] = { ' ' };
+             
+             ty->state.wrapnext = 0;
+             ty->state.insert = 1;
+             for (i = 0; i < arg; i++)
+               _text_append(ty, blank, 1);
+             ty->state.insert = pi;
+          }
+        break;
+      case 'A': // cursor up N
+      case 'e': // cursor up N
+        arg = _csi_arg_get(&b);
+        if (arg < 1) arg = 1;
+        ty->state.wrapnext = 0;
+        for (i = 0; i < arg; i++)
+          {
+             ty->state.cy--;
+             _text_scroll_rev_test(ty);
+          }
+        break;
+      case 'B': // cursor down N
+        arg = _csi_arg_get(&b);
+        if (arg < 1) arg = 1;
+        ty->state.wrapnext = 0;
+        for (i = 0; i < arg; i++)
+          {
+             ty->state.cy++;
+             _text_scroll_test(ty);
+          }
+        break;
+      case 'D': // cursor left N
+        arg = _csi_arg_get(&b);
+        if (arg < 1) arg = 1;
+        ty->state.wrapnext = 0;
+        for (i = 0; i < arg; i++)
+          {
+             ty->state.cx--;
+             if (ty->state.cx < 0) ty->state.cx = 0;
+          }
+        break;
+      case 'C': // cursor right N
+      case 'a': // cursor right N
+        arg = _csi_arg_get(&b);
+        if (arg < 1) arg = 1;
+        ty->state.wrapnext = 0;
+        for (i = 0; i < arg; i++)
+          {
+             ty->state.cx++;
+             if (ty->state.cx >= ty->w) ty->state.cx = ty->w - 1;
+          }
+        break;
+      case 'H': // cursor pos set
+      case 'f': // cursor pos set
+        ty->state.wrapnext = 0;
+        if (!*b)
+          {
+             ty->state.cx = 0;
+             ty->state.cy = 0;
+          }
+        else
+          {
+             arg = _csi_arg_get(&b);
+             if (arg < 1) arg = 1;
+             arg--;
+             if (arg < 0) arg = 0;
+             else if (arg >= ty->h) arg = ty->h - 1;
+             if (b) ty->state.cy = arg;
+             if (b)
+               {
+                  arg = _csi_arg_get(&b);
+                  if (arg < 1) arg = 1;
+                  arg--;
+               }
+             else arg = 0;
+             if (arg < 0) arg = 0;
+             else if (arg >= ty->w) arg = ty->w - 1;
+             if (b) ty->state.cx = arg;
+          }
+       break;
+      case 'G': // to column N
+        arg = _csi_arg_get(&b);
+        if (arg < 1) arg = 1;
+        ty->state.wrapnext = 0;
+        ty->state.cx = arg - 1;
+        if (ty->state.cx < 0) ty->state.cx = 0;
+        else if (ty->state.cx >= ty->w) ty->state.cx = ty->w - 1;
+        break;
+      case 'd': // to row N
+        arg = _csi_arg_get(&b);
+        if (arg < 1) arg = 1;
+        ty->state.wrapnext = 0;
+        ty->state.cy = arg - 1;
+        if (ty->state.cy < 0) ty->state.cy = 0;
+        else if (ty->state.cy >= ty->h) ty->state.cy = ty->h - 1;
+        break;
+      case 'E': // down relative N rows, and to col 0
+        arg = _csi_arg_get(&b);
+        if (arg < 1) arg = 1;
+        ty->state.wrapnext = 0;
+        ty->state.cy += arg;
+        if (ty->state.cy < 0) ty->state.cy = 0;
+        else if (ty->state.cy >= ty->h) ty->state.cy = ty->h - 1;
+        ty->state.cx = 0;
+        break;
+      case 'F': // up relative N rows, and to col 0
+        arg = _csi_arg_get(&b);
+        if (arg < 1) arg = 1;
+        ty->state.wrapnext = 0;
+        ty->state.cy -= arg;
+        if (ty->state.cy < 0) ty->state.cy = 0;
+        else if (ty->state.cy >= ty->h) ty->state.cy = ty->h - 1;
+        ty->state.cx = 0;
+        break;
+      case 'X': // erase N chars
+        arg = _csi_arg_get(&b);
+        if (arg < 1) arg = 1;
+        _clear_line(ty, CLR_END, arg);
+        break;
+      case 'S': // scroll up N lines
+        arg = _csi_arg_get(&b);
+        if (arg < 1) arg = 1;
+        for (i = 0; i < arg; i++) _text_scroll(ty);
+        break;
+      case 'T': // scroll down N lines
+        arg = _csi_arg_get(&b);
+        if (arg < 1) arg = 1;
+        for (i = 0; i < arg; i++) _text_scroll_rev(ty);
+        break;
+      case 'M': // delete N lines - cy
+      case 'L': // insert N lines - cy
+        arg = _csi_arg_get(&b);
+          {
+             int sy1, sy2;
+             
+             sy1 = ty->state.scroll_y1;
+             sy2 = ty->state.scroll_y2;
+             if (ty->state.scroll_y2 == 0)
+               {
+                  ty->state.scroll_y1 = ty->state.cy;
+                  ty->state.scroll_y2 = ty->h;
+               }
+             else
+               {
+                  ty->state.scroll_y1 = ty->state.cy;
+                  if (ty->state.scroll_y2 <= ty->state.scroll_y1)
+                    ty->state.scroll_y2 = ty->state.scroll_y1 + 1;
+               }
+             if (arg < 1) arg = 1;
+             for (i = 0; i < arg; i++)
+               {
+                  if (*cc == 'M') _text_scroll(ty);
+                  else _text_scroll_rev(ty);
+               }
+             ty->state.scroll_y1 = sy1;
+             ty->state.scroll_y2 = sy2;
+          }
+        break;
+      case 'P': // erase and scrollback N chars
+        arg = _csi_arg_get(&b);
+          {
+             Termcell *cells;
+             int x, lim;
+             
+             if (arg < 1) arg = 1;
+             cells = &(ty->screen[ty->state.cy * ty->w]);
+             lim = ty->w - arg;
+             for (x = ty->state.cx; x < (ty->w); x++)
+               {
+                  if (x < lim)
+                    cells[x] = cells[x + arg];
+                  else
+                    memset(&(cells[x]), 0, sizeof(*cells));
+               }
+          }
+        break;
+      case 'c': // query device id
+          {
+             char bf[32];
+//             0  Base VT100, no options
+//             1  Preprocessor option (STP)
+//             2  Advanced video option (AVO)
+//             3  AVO and STP
+//             4  Graphics processor option (GO)
+//             5  GO and STP
+//             6  GO and AVO
+//             7  GO, STP, and AVO
+             snprintf(bf, sizeof(bf), "\033[?1;%ic", 0);
+             _term_write(ty, bf, strlen(bf));
+          }
+        break;
+      case 'J': // "2j" erases the screen, 1j erase from screen start to curs, 0j erase cursor to end of screen
+        arg = _csi_arg_get(&b);
+        if (b)
+          {
+             if ((arg >= CLR_END) && (arg <= CLR_ALL))
+               _clear_screen(ty, arg);
+             else
+               ERR("invalid clr scr %i\n", arg);
+          }
+        else _clear_screen(ty, CLR_END);
+        break;
+      case 'K': // 0K erase to end of line, 1K erase from screen start to cursor, 2K erase all of line
+        arg = _csi_arg_get(&b);
+        if (b)
+          {
+             if ((arg >= CLR_END) && (arg <= CLR_ALL))
+               _clear_line(ty, arg, ty->w);
+             else
+               ERR("invalid clr lin %i\n", arg);
+          }
+        else _clear_line(ty, CLR_END, ty->w);
+        break;
+      case 'h': // list - set screen mode or line wrap ("7h" == turn on line wrap, "7l" disables line wrap , ...)
+      case 'l':
+          {
+             int mode = 0, priv = 0;
+             int handled = 0;
+             
+             if (*cc == 'h') mode = 1;
+             if (*b == '?')
+               {
+                  priv = 1;
+                  b++;
+               }
+             if (priv)
+               {
+                  while (b)
+                    {
+                       arg = _csi_arg_get(&b);
+                       if (b)
+                         {
+                            int i, size;
+                                      
+                            switch (arg)
+                              {
+                               case 1:
+                                 handled = 1;
+                                 ty->state.appcursor = mode;
+                                 break;
+                               case 5:
+                                 handled = 1;
+                                 break;
+                               case 7:
+                                 handled = 1;
+                                 DBG("DDD: set wrap mode to %i\n", mode);
+                                 ty->state.wrap = mode;
+                                 break;
+                               case 20:
+                                 ty->state.crlf = mode;
+                                 break;
+                               case 12:
+                                 handled = 1;
+//                                 DBG("XXX: set blinking cursor to (stop?) %i\n", mode);
+                                 break;
+                               case 25:
+                                 handled = 1;
+                                 ty->state.hidecursor = !mode;
+                                 break;
+                               case 1000:
+                                 handled = 1;
+                                 INF("XXX: set x11 mouse reporting to %i\n", mode);
+                                 break;
+                               case 1049:
+                               case 47:
+                               case 1047:
+                                 handled = 1;
+                                 DBG("DDD: switch buf\n");
+                                 if (ty->altbuf)
+                                   {
+                                      // if we are looking at alt buf now,
+                                      // clear main buf before we swap it back
+                                      // into the sreen2 save (so save is
+                                      // clear)
+                                      _clear_all(ty);
+//                                      _cursor_copy(&(ty->swap), &(ty->state));
+                                      ty->state = ty->swap;
+                                   }
+                                 else
+                                   {
+//                                      _cursor_copy(&(ty->state), &(ty->swap));
+                                      ty->swap = ty->state;
+                                   }
+                                 size = ty->w * ty->h;
+                                 // swap screen content now
+                                 for (i = 0; i < size; i++)
+                                   {
+                                      Termcell t;
+                                      
+                                      t = ty->screen[i];
+                                      ty->screen[i] = ty->screen2[i];
+                                      ty->screen2[i] = t;
+                                   }
+                                 ty->altbuf = !ty->altbuf;
+                                 if (ty->cb.cancel_sel.func)
+                                   ty->cb.cancel_sel.func(ty->cb.cancel_sel.data);
+                                 break;
+                               case 1048:
+                                 if (mode)
+                                   _cursor_copy(&(ty->state), &(ty->save));
+                                 else
+                                   _cursor_copy(&(ty->save), &(ty->state));
+                                 break;
+                               default:
+                                 ERR("unhandled screen mode arg %i\n", arg);
+                                 break;
+                              }
+                         }
+                    }
+               }
+             else
+               {
+                  while (b)
+                    {
+                       arg = _csi_arg_get(&b);
+                       if (b)
+                         {
+                            if (arg == 1)
+                              {
+                                 handled = 1;
+                                 ty->state.appcursor = mode;
+                              }
+                            else if (arg == 4)
+                              {
+                                 handled = 1;
+                                 DBG("DDD: set insert mode to %i\n", mode);
+                                 ty->state.insert = mode;
+                              }
+//                            else if (arg == 24)
+//                              {
+//                                 ERR("unhandled #24 arg %i\n", arg);
+//                                  // ???
+//                              }
+                            else
+                              ERR("unhandled screen non-priv mode arg %i, mode %i, ch '%c'\n", arg, mode, *cc);
+                         }
+                    }
+               }
+             if (!handled) ERR("unhandled '%c' : '%s'\n", *cc, buf);
+          }
+        break;
+      case 'r':
+        arg = _csi_arg_get(&b);
+        if (!b)
+          {
+             INF("no region args reset region\n");
+             ty->state.scroll_y1 = 0;
+             ty->state.scroll_y2 = 0;
+          }
+        else
+          {
+             int arg2;
+             
+             arg2 = _csi_arg_get(&b);
+             if (!b)
+               {
+                  INF("failed to give 2 region args reset region\n");
+                  ty->state.scroll_y1 = 0;
+                  ty->state.scroll_y2 = 0;
+               }
+             else
+               {
+                  if (arg >= arg2)
+                    {
+                       ERR("scroll region beginning >= end [%i %i]\n", arg, arg2);
+                       ty->state.scroll_y1 = 0;
+                       ty->state.scroll_y2 = 0;
+                    }
+                  else
+                    {
+                       INF("2 region args: %i %i\n", arg, arg2);
+                       if (arg >= ty->h) arg = ty->h - 1;
+                       if (arg2 > ty->h) arg2 = ty->h;
+                       arg2++;
+                       ty->state.scroll_y1 = arg - 1;
+                       ty->state.scroll_y2 = arg2 - 1;
+                    }
+               }
+          }
+        break;
+      case 's': // store cursor pos
+        _cursor_copy(&(ty->state), &(ty->save));
+        break;
+      case 'u': // restore cursor pos
+        _cursor_copy(&(ty->save), &(ty->state));
+        break;
+/*        
+      case 'R': // report cursor
+        break;
+      case 'n': // "6n" queires cursor pos, 0n, 3n, 5n too
+        break;
+      case 's':
+        break;
+      case 't':
+        break;
+      case 'p': // define key assignments based on keycode
+        break;
+      case 'q': // set/clear led's
+        break;
+      case 'x': // request terminal parameters
+        break;
+      case 'r': // set top and bottom margins
+        break;
+      case 'y': // invoke confidence test
+        break;
+      case 'g': // clear tabulation
+        break;
+ */
+      default:
+        ERR("unhandled CSI '%c' (0x%02x), buf='%s'\n", *cc, *cc, buf);
+        break;
+     }
+   cc++;
+   return cc - c;
+}
+
+static int
+_handle_esc_xterm(Termpty *ty, const int *c, int *ce)
+{
+   int *cc;
+   char buf[4096], *b;
+   
+   cc = (int *)c;
+   b = buf;
+   while ((cc < ce) && (*cc >= ' ') && (*cc < 0x7f))
+     {
+        *b = *cc;
+        b++;
+        cc++;
+     }
+   *b = 0;
+   if ((*cc < ' ') || (*cc >= 0x7f)) cc++;
+   else return -2;
+   switch (buf[0])
+     {
+      case '0':
+        // XXX: title + name - callback
+        b = &(buf[2]);
+        if (ty->prop.title) eina_stringshare_del(ty->prop.title);
+        if (ty->prop.icon) eina_stringshare_del(ty->prop.icon);
+        ty->prop.title = eina_stringshare_add(b);
+        ty->prop.icon = eina_stringshare_add(b);
+        if (ty->cb.set_title.func) ty->cb.set_title.func(ty->cb.set_title.data);
+        if (ty->cb.set_icon.func) ty->cb.set_title.func(ty->cb.set_icon.data);
+        break;
+      case '1':
+        // XXX: icon name - callback
+        b = &(buf[2]);
+        if (ty->prop.icon) eina_stringshare_del(ty->prop.icon);
+        ty->prop.icon = eina_stringshare_add(b);
+        if (ty->cb.set_icon.func) ty->cb.set_title.func(ty->cb.set_icon.data);
+        break;
+      case '2':
+        // XXX: title - callback
+        b = &(buf[2]);
+        if (ty->prop.title) eina_stringshare_del(ty->prop.title);
+        ty->prop.title = eina_stringshare_add(b);
+        if (ty->cb.set_title.func) ty->cb.set_title.func(ty->cb.set_title.data);
+        break;
+      case '4':
+        // XXX: set palette entry. not supported.
+        b = &(buf[2]);
+        break;
+      default:
+        // many others
+        ERR("unhandled xterm esc '%c' -> '%s'\n", buf[0], buf);
+        break;
+     }
+    return cc - c;
+}
+
+static int
+_handle_esc(Termpty *ty, const int *c, int *ce)
+{
+   if ((ce - c) < 2) return 0;
+   DBG("ESC: '%c'\n", c[1]);
+   switch (c[1])
+     {
+      case '[':
+        return 2 + _handle_esc_csi(ty, c + 2, ce);
+      case ']':
+        return 2 + _handle_esc_xterm(ty, c + 2, ce);
+      case '=': // set alternate keypad mode
+        ty->state.alt_kp = 1;
+        return 2;
+      case '>': // set numeric keypad mode
+        ty->state.alt_kp = 0;
+        return 2;
+      case 'M': // move to prev line
+        ty->state.wrapnext = 0;
+        ty->state.cy--;
+        _text_scroll_rev_test(ty);
+        return 2;
+      case 'D': // move to next line
+        ty->state.wrapnext = 0;
+        ty->state.cy++;
+        _text_scroll_test(ty);
+        return 2;
+      case 'E': // add \n\r
+        ty->state.wrapnext = 0;
+        ty->state.cx = 0;
+        ty->state.cy++;
+        _text_scroll_test(ty);
+        return 2;
+      case 'Z': // same a 'ESC [ Pn c'
+        _term_txt_write(ty, "\033[?1;2C");
+        return 2;
+      case 'c': // reset terminal to initial state
+        DBG("reset to init mode and clear\n");
+        _reset_state(ty);
+        _clear_screen(ty, CLR_ALL);
+        if (ty->cb.cancel_sel.func)
+          ty->cb.cancel_sel.func(ty->cb.cancel_sel.data);
+        return 2;
+      case '(': // charset 0
+        ty->state.chset[0] = c[2];
+        ty->state.multibyte = 0;
+        return 3;
+      case ')': // charset 1
+        ty->state.chset[1] = c[2];
+        ty->state.multibyte = 0;
+        return 3;
+      case '*': // charset 2
+        ty->state.chset[2] = c[2];
+        ty->state.multibyte = 0;
+        return 3;
+      case '+': // charset 3
+        ty->state.chset[3] = c[2];
+        ty->state.multibyte = 0;
+        return 3;
+      case '$': // charset -2
+        ty->state.chset[2] = c[2];
+        ty->state.multibyte = 1;
+        return 3;
+      case '#': // #8 == test mode -> fill screen with "E";
+        if (c[2] == '8')
+          {
+             int i, size;
+             Termcell *cells;
+             
+             DBG("reset to init mode and clear then fill with E\n");
+             _reset_state(ty);
+             ty->save = ty->state;
+             ty->swap = ty->state;
+             _clear_screen(ty, CLR_ALL);
+             if (ty->cb.cancel_sel.func)
+               ty->cb.cancel_sel.func(ty->cb.cancel_sel.data);
+             cells = ty->screen;
+             size = ty->w * ty->h;
+             if (cells)
+               {
+                  for (i = 0; i < size; i++) cells[i].glyph = 'E';
+               }
+          }
+        return 3;
+      case '@': // just consume this plus next char
+        return 3;
+      case '7': // save cursor pos
+        _cursor_copy(&(ty->state), &(ty->save));
+        return 2;
+      case '8': // restore cursor pos
+        _cursor_copy(&(ty->save), &(ty->state));
+        return 2;
+/*        
+      case 'G': // query gfx mode
+        return 3;
+      case 'H': // set tab at current column
+        return 2;
+      case 'n': // single shift 2
+        return 2;
+      case 'o': // single shift 3
+        return 2;
+ */
+      default:
+        ERR("eek - esc unhandled '%c' (0x%02x)\n", c[1], c[1]);
+        break;
+     }
+   return 1;
+}
+
+static int
+_handle_seq(Termpty *ty, const int *c, int *ce)
+{
+   int *cc, len = 0;
+   
+   if (c[0] < 0x20)
+     {
+        switch (c[0])
+          {
+/*             
+           case 0x00: // NUL
+             return 1;
+           case 0x01: // SOH (start of heading)
+             return 1;
+           case 0x02: // STX (start of text)
+             return 1;
+           case 0x03: // ETX (end of text)
+             return 1;
+           case 0x04: // EOT (end of transmission)
+             return 1;
+ */
+           case 0x05: // ENQ (enquiry)
+             _term_txt_write(ty, "ABC\r\n");
+             ty->state.had_cr = 0;
+             return 1;
+/*            
+           case 0x06: // ACK (acknowledge)
+             return 1;
+ */
+           case 0x07: // BEL '\a' (bell)
+             INF("BEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEP\n");
+             ty->state.had_cr = 0;
+             return 1;
+           case 0x08: // BS  '\b' (backspace)
+             DBG("->BS\n");
+             ty->state.wrapnext = 0;
+             ty->state.cx--;
+             if (ty->state.cx < 0) ty->state.cx = 0;
+             ty->state.had_cr = 0;
+             return 1;
+           case 0x09: // HT  '\t' (horizontal tab)
+             DBG("->HT\n");
+             ty->screen[ty->state.cx + (ty->state.cy * ty->w)].att.tab = 1;
+             ty->state.wrapnext = 0;
+             ty->state.cx += 8;
+             ty->state.cx = (ty->state.cx / 8) * 8;
+             if (ty->state.cx >= ty->w)
+               ty->state.cx = ty->w - 1;
+             ty->state.had_cr = 0;
+             return 1;
+           case 0x0a: // LF  '\n' (new line) 
+           case 0x0b: // VT  '\v' (vertical tab)
+           case 0x0c: // FF  '\f' (form feed)
+             DBG("->LF\n");
+             if (ty->state.had_cr)
+               ty->screen[ty->state.had_cr_x + (ty->state.had_cr_y * ty->w)].att.newline = 1;
+             ty->state.wrapnext = 0;
+             if (ty->state.crlf) ty->state.cx = 0;
+             ty->state.cy++;
+             _text_scroll_test(ty);
+             ty->state.had_cr = 0;
+             return 1;
+           case 0x0d: // CR  '\r' (carriage ret)
+             DBG("->CR\n");
+             if (ty->state.cx != 0)
+               {
+                  ty->state.had_cr_x = ty->state.cx;
+                  ty->state.had_cr_y = ty->state.cy;
+               }
+             ty->state.wrapnext = 0;
+             ty->state.cx = 0;
+             ty->state.had_cr = 1;
+             return 1;
+/*             
+           case 0x0e: // SO  (shift out) // Maps G1 character set into GL.
+             return 1;
+           case 0x0f: // SI  (shift in) // Maps G0 character set into GL.
+             return 1;
+           case 0x10: // DLE (data link escape)
+             return 1;
+           case 0x11: // DC1 (device control 1)
+             return 1;
+           case 0x12: // DC2 (device control 2)
+             return 1;
+           case 0x13: // DC3 (device control 3)
+             return 1;
+           case 0x14: // DC4 (device control 4)
+             return 1;
+           case 0x15: // NAK (negative ack.)
+             return 1;
+           case 0x16: // SYN (synchronous idle)
+             return 1;
+           case 0x17: // ETB (end of trans. blk)
+             return 1;
+           case 0x18: // CAN (cancel)
+             return 1;
+           case 0x19: // EM  (end of medium)
+             return 1;
+           case 0x1a: // SUB (substitute)
+             return 1;
+ */
+           case 0x1b: // ESC (escape)
+             ty->state.had_cr = 0;
+             return _handle_esc(ty, c, ce);
+/*             
+           case 0x1c: // FS  (file separator)
+             return 1;
+           case 0x1d: // GS  (group separator)
+             return 1;
+           case 0x1e: // RS  (record separator)
+             return 1;
+           case 0x1f: // US  (unit separator)
+             return 1;
+ */
+           default:
+             ERR("unhandled char 0x%02x\n", c[0]);
+             ty->state.had_cr = 0;
+             return 1;
+          }
+     }
+   else if (c[0] == 0xf7) // DEL
+     {
+        ERR("unhandled char 0x%02x [DEL]\n", c[0]);
+        ty->state.had_cr = 0;
+        return 1;
+     }
+        
+   cc = (int *)c;
+   DBG("txt: [");
+   while ((cc < ce) && (*cc >= 0x20) && (*cc != 0xf7))
+     {
+        DBG("%c", *cc);
+        cc++;
+        len++;
+     }
+   DBG("]\n");
+   _text_append(ty, c, len);
+   ty->state.had_cr = 0;
+   return len;
+}
+
+static void
+_handle_buf(Termpty *ty, const int *glyphs, int len)
+{
+   int *c, *ce, n, *b, bytes;
+   
+   c = (int *)glyphs;
+   ce = &(c[len]);
+
+   if (ty->buf)
+     {
+        bytes = (ty->buflen + len + 1) * sizeof(int);
+        b = realloc(ty->buf, bytes);
+        if (!b)
+          {
+             ERR("memerr\n");
+          }
+        INF("realloc add %i + %i\n", (int)(ty->buflen * sizeof(int)), (int)(len * sizeof(int)));
+        bytes = len * sizeof(int);
+        memcpy(&(b[ty->buflen]), glyphs, bytes);
+        ty->buf = b;
+        ty->buflen += len;
+        ty->buf[ty->buflen] = 0;
+        c = ty->buf;
+        ce = c + ty->buflen;
+        while (c < ce)
+          {
+             n = _handle_seq(ty, c, ce);
+             if (n == 0)
+               {
+                  int *tmp = ty->buf;
+                  ty->buf = NULL;
+                  ty->buflen = 0;
+                  bytes = ((char *)ce - (char *)c) + sizeof(int);
+                  INF("malloc til %i\n", (int)(bytes - sizeof(int)));
+                  ty->buf = malloc(bytes);
+                  if (!ty->buf)
+                    {
+                       ERR("memerr\n");
+                    }
+                  bytes = (char *)ce - (char *)c;
+                  memcpy(ty->buf, c, bytes);
+                  ty->buflen = bytes / sizeof(int);
+                  ty->buf[ty->buflen] = 0;
+                  free(tmp);
+                  break;
+               }
+             c += n;
+          }
+        if (c == ce)
+          {
+             if (ty->buf)
+               {
+                  free(ty->buf);
+                  ty->buf = NULL;
+               }
+             ty->buflen = 0;
+          }
+     }
+   else
+     {
+        while (c < ce)
+          {
+             n = _handle_seq(ty, c, ce);
+             if (n == 0)
+               {
+                  bytes = ((char *)ce - (char *)c) + sizeof(int);
+                  ty->buf = malloc(bytes);
+                  INF("malloc %i\n", (int)(bytes - sizeof(int)));
+                  if (!ty->buf)
+                    {
+                       ERR("memerr\n");
+                    }
+                  bytes = (char *)ce - (char *)c;
+                  memcpy(ty->buf, c, bytes);
+                  ty->buflen = bytes / sizeof(int);
+                  ty->buf[ty->buflen] = 0;
+                  break;
+               }
+             c += n;
+          }
+     }
+}
+
+static void
+_pty_size(Termpty *ty)
+{
+   struct winsize sz;
+   
+   sz.ws_col = ty->w;
+   sz.ws_row = ty->h;
+   sz.ws_xpixel = 0;
+   sz.ws_ypixel = 0;
+   if (ioctl(ty->fd, TIOCSWINSZ, &sz) < 0) perror("Size set ioctl failed\n");
+}
+
+static Eina_Bool
+_cb_exe_exit(void *data, int type, void *event)
+{
+   Ecore_Exe_Event_Del *ev = event;
+   Termpty *ty = data;
+   
+   if (ev->pid != ty->pid) return ECORE_CALLBACK_PASS_ON;
+   // XXX: report via cb
+   exit(ev->exit_code);
+   return ECORE_CALLBACK_PASS_ON;
+}
+
+static Eina_Bool
+_cb_fd_read(void *data, Ecore_Fd_Handler *fd_handler)
+{
+   Termpty *ty = data;
+   char buf[4097];
+   int glyph[4097];
+   int len, i, j, reads;
+
+   // read up to 64 * 4096 bytes
+   for (reads = 0; reads < 64; reads++)
+     {
+        len = read(ty->fd, buf, sizeof(buf) - 1);
+        if (len <= 0) break;
+        buf[len] = 0;
+        // convert UTF8 to glyph integers
+        j = 0;
+        for (i = 0; i < len;)
+          {
+             int g = 0;
+             
+             if (buf[i])
+               {
+                  i = evas_string_char_next_get(buf, i, &g);
+                  if (i < 0) break;
+//                  DBG("(%i) %02x '%c'\n", j, g, g);
+               }
+             else
+               {
+                  ERR("ZERO GLYPH!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
+                  g = 0;
+                  i++;
+               }
+             glyph[j] = g;
+             j++;
+          }
+        glyph[j] = 0;
+//        DBG("---------------- handle buf %i\n", j);
+        _handle_buf(ty, glyph, j);
+     }
+   if (ty->cb.change.func) ty->cb.change.func(ty->cb.change.data);
+   return EINA_TRUE;
+}
+
+static void
+_limit_coord(Termpty *ty, Termstate *state)
+{
+   state->wrapnext = 0;
+   if (state->cx >= ty->w) state->cx = ty->w - 1;
+   if (state->cy >= ty->h) state->cy = ty->h - 1;
+   if (state->had_cr_x >= ty->w) state->had_cr_x = ty->w - 1;
+   if (state->had_cr_y >= ty->h) state->had_cr_y = ty->h - 1;
+}
+
+Termpty *
+termpty_new(const char *cmd, int w, int h, int backscroll)
+{
+   Termpty *ty;
+   const char *pty;
+   
+   ty = calloc(1, sizeof(Termpty));
+   if (!ty) return NULL;
+   ty->w = w;
+   ty->h = h;
+   ty->backmax = backscroll;
+
+   _reset_state(ty);
+   ty->save = ty->state;
+   ty->swap = ty->state;
+   
+   ty->screen = calloc(1, sizeof(Termcell) * ty->w * ty->h);
+   if (!ty->screen) goto err;
+   ty->screen2 = calloc(1, sizeof(Termcell) * ty->w * ty->h);
+   if (!ty->screen2) goto err;
+   
+   ty->fd = posix_openpt(O_RDWR | O_NOCTTY);
+   if (ty->fd < 0) goto err;
+   if (grantpt(ty->fd) != 0) goto err;
+   if (unlockpt(ty->fd) != 0) goto err;
+   pty = ptsname(ty->fd);
+   ty->slavefd = open(pty, O_RDWR | O_NOCTTY);
+   if (ty->slavefd < 0) goto err;
+   fcntl(ty->fd, F_SETFL, O_NDELAY);
+
+   ty->hand_exe_exit = ecore_event_handler_add(ECORE_EXE_EVENT_DEL,
+                                               _cb_exe_exit, ty);
+   ty->pid = fork();
+   if (!ty->pid)
+     {
+        char **args, *shell;
+        struct passwd *pw;
+        uid_t uid;
+        int i;
+
+        for (i = 0; i < 100; i++)
+          {
+             if (i != ty->slavefd) close(i);
+          }
+        ty->fd = ty->slavefd;
+        setsid();
+        
+        dup2(ty->fd, 0);
+        dup2(ty->fd, 1);
+        dup2(ty->fd, 2);
+        
+        if (ioctl(ty->fd, TIOCSCTTY, NULL) < 0) exit(1);
+        
+        uid = getuid();
+        pw = getpwuid(uid);
+        if (!pw) shell = "/bin/sh";
+        shell = pw->pw_shell;
+        if (!shell) shell = "/bin/sh";
+        if (!cmd) cmd = shell;
+        args = malloc(2 * sizeof(char *));
+        args[0] = (char *)cmd;
+        args[1] = NULL;
+        // pretend to be xterm
+        putenv("TERM=xterm");
+        execvp(args[0], args);
+        exit(1);
+     }
+   ty->hand_fd = ecore_main_fd_handler_add(ty->fd, ECORE_FD_READ,
+                                           _cb_fd_read, ty,
+                                           NULL, NULL);
+   close(ty->slavefd);
+   _pty_size(ty);
+   return ty;
+err:
+   if (ty->screen) free(ty->screen);
+   if (ty->screen2) free(ty->screen2);
+   if (ty->fd >= 0) close(ty->fd);
+   if (ty->slavefd >= 0) close(ty->slavefd);
+   free(ty);
+   return NULL;
+}
+
+void
+termpty_free(Termpty *ty)
+{
+   if (ty->hand_exe_exit) ecore_event_handler_del(ty->hand_exe_exit);
+   if (ty->hand_fd) ecore_main_fd_handler_del(ty->hand_fd);
+   if (ty->prop.title) eina_stringshare_del(ty->prop.title);
+   if (ty->prop.icon) eina_stringshare_del(ty->prop.icon);
+   if (ty->fd >= 0) close(ty->fd);
+   if (ty->slavefd >= 0) close(ty->slavefd);
+   if (ty->back)
+     {
+        int i;
+        
+        for (i = 0; i < ty->backmax; i++)
+          {
+             if (ty->back[i]) free(ty->back[i]);
+          }
+        free(ty->back);
+     }
+   if (ty->screen) free(ty->screen);
+   if (ty->screen2) free(ty->screen2);
+   if (ty->buf) free(ty->buf);
+   memset(ty, 0, sizeof(Termpty));
+   free(ty);
+}
+
+Termcell *
+termpty_cellrow_get(Termpty *ty, int y, int *wret)
+{
+   Termsave *ts;
+   
+   if (y >= 0)
+     {
+        if (y >= ty->h) return NULL;
+        *wret = ty->w;
+        return &(ty->screen[y * ty->w]);
+     }
+   if (y < -ty->backmax) return NULL;
+   ts = ty->back[(ty->backmax + ty->backpos + y) % ty->backmax];
+   if (!ts) return NULL;
+   *wret = ts->w;
+   return ts->cell;
+}
+
+void
+termpty_write(Termpty *ty, const char *input, int len)
+{
+   if (write(ty->fd, input, len) < 0) perror("write");
+}
+
+void
+termpty_resize(Termpty *ty, int w, int h)
+{
+   Termcell *olds, *olds2;
+   int y, ww, hh, oldw, oldh;
+   
+   if ((ty->w == w) && (ty->h == h)) return;
+
+   olds = ty->screen;
+   olds2 = ty->screen2;
+   oldw = ty->w;
+   oldh = ty->h;
+   
+   ty->w = w;
+   ty->h = h;
+   ty->state.had_cr = 0;
+   _limit_coord(ty, &(ty->state));
+   _limit_coord(ty, &(ty->swap));
+   _limit_coord(ty, &(ty->save));
+   
+   ty->screen = calloc(1, sizeof(Termcell) * ty->w * ty->h);
+   if (!ty->screen)
+     {
+        ty->screen2 = NULL;
+        ERR("memerr");
+     }
+   ty->screen2 = calloc(1, sizeof(Termcell) * ty->w * ty->h);
+   if (!ty->screen2)
+     {
+        ERR("memerr");
+     }
+   
+   ww = ty->w;
+   hh = ty->h;
+   if (ww > oldw) ww = oldw;
+   if (hh > oldh) hh = oldh;
+
+   for (y = 0; y < hh; y++)
+     {
+        Termcell *c1, *c2;
+        
+        c1 = &(olds[y * oldw]);
+        c2 = &(ty->screen[y * ty->w]);
+        _text_copy(ty, c1, c2, ww);
+        
+        c1 = &(olds2[y * oldw]);
+        c2 = &(ty->screen2[y * ty->w]);
+        _text_copy(ty, c1, c2, ww);
+     }
+
+   free(olds);
+   free(olds2);
+
+   _pty_size(ty);
+}
diff --git a/src/bin/termpty.h b/src/bin/termpty.h
new file mode 100644 (file)
index 0000000..7065da6
--- /dev/null
@@ -0,0 +1,105 @@
+typedef struct _Termpty   Termpty;
+typedef struct _Termcell  Termcell;
+typedef struct _Termatt   Termatt;
+typedef struct _Termstate Termstate;
+typedef struct _Termsave  Termsave;
+
+#define COL_DEF        0
+#define COL_BLACK      1
+#define COL_RED        2
+#define COL_GREEN      3
+#define COL_YELLOW     4
+#define COL_BLUE       5
+#define COL_MAGENTA    6
+#define COL_CYAN       7
+#define COL_WHITE      8
+
+#define COL_INVERSE    9
+#define COL_INVERSEBG 10
+
+struct _Termatt
+{
+   unsigned char fg, bg;
+   unsigned short bold : 1;
+   unsigned short faint : 1;
+   unsigned short italic : 1;
+   unsigned short underline : 1;
+   unsigned short blink : 1;
+   unsigned short blink2 : 1;
+   unsigned short inverse : 1;
+   unsigned short invisible : 1;
+   unsigned short strike : 1;
+   unsigned short fg256 : 1;
+   unsigned short bg256 : 1;
+   // below used for working out text from selections
+   unsigned short autowrapped : 1;
+   unsigned short newline : 1;
+   unsigned short tab : 1;
+   // 2 bits left
+};
+
+struct _Termstate
+{
+   int           cx, cy;
+   Termatt       att;
+   unsigned char charset;
+   unsigned char charsetch;
+   unsigned char chset[4];
+   int           scroll_y1, scroll_y2;
+   int           had_cr_x, had_cr_y;
+   unsigned int  multibyte : 1;
+   unsigned int  alt_kp : 1;
+   unsigned int  insert : 1;
+   unsigned int  appcursor : 1;
+   unsigned int  wrap : 1;
+   unsigned int  wrapnext : 1;
+   unsigned int  hidecursor : 1;
+   unsigned int  crlf : 1;
+   unsigned int  had_cr : 1;
+};
+
+struct _Termpty
+{
+   Ecore_Event_Handler *hand_exe_exit;
+   Ecore_Fd_Handler *hand_fd;
+   struct {
+      struct {
+         void (*func) (void *data);
+         void *data;
+      } change, scroll, set_title, set_icon, cancel_sel;
+   } cb;
+   struct {
+      const char *title;
+      const char *icon;
+   } prop;
+   int w, h;
+   int fd, slavefd;
+   pid_t pid;
+   Termcell *screen, *screen2;
+   Termsave **back;
+   int backmax, backpos;
+   int backscroll_num;
+   int *buf;
+   int buflen;
+   Termstate state, save, swap;
+   unsigned int altbuf : 1;
+};
+
+struct _Termcell
+{
+   int      glyph;
+   Termatt  att;
+};
+
+struct _Termsave
+{
+   int w;
+   Termcell cell[1];
+};
+
+Termpty  *termpty_new(const char *cmd, int w, int h, int backscroll);
+void      termpty_free(Termpty *ty);
+Termcell *termpty_cellrow_get(Termpty *ty, int y, int *wret);
+void      termpty_write(Termpty *ty, const char *input, int len);
+void      termpty_resize(Termpty *ty, int w, int h);
+
diff --git a/src/bin/utf8.c b/src/bin/utf8.c
new file mode 100644 (file)
index 0000000..1de8669
--- /dev/null
@@ -0,0 +1,56 @@
+#include "utf8.h"
+
+void
+glyph_to_utf8(int g, char *txt)
+{
+   if (g < (1 << (7)))
+     { // 0xxxxxxx
+        txt[0] = g & 0x7f;
+        txt[1] = 0;
+     }
+   else if (g < (1 << (5 + 6)))
+     { // 110xxxxx 10xxxxxx
+        txt[0] = 0xc0 | ((g >> 6) & 0x1f);
+        txt[1] = 0x80 | ((g     ) & 0x3f);
+        txt[2] = 0;
+     }
+   else if (g < (1 << (4 + 6 + 6)))
+     { // 1110xxxx 10xxxxxx 10xxxxxx
+        txt[0] = 0xe0 | ((g >> 12) & 0x0f);
+        txt[1] = 0x80 | ((g >> 6 ) & 0x3f);
+        txt[2] = 0x80 | ((g      ) & 0x3f);
+        txt[3] = 0;
+     }
+   else if (g < (1 << (3 + 6 + 6 + 6)))
+     { // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+        txt[0] = 0xf0 | ((g >> 18) & 0x07);
+        txt[1] = 0x80 | ((g >> 12) & 0x3f);
+        txt[2] = 0x80 | ((g >> 6 ) & 0x3f);
+        txt[3] = 0x80 | ((g      ) & 0x3f);
+        txt[4] = 0;
+     }
+   else if (g < (1 << (2 + 6 + 6 + 6 + 6)))
+     { // 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
+        txt[0] = 0xf8 | ((g >> 24) & 0x03);
+        txt[1] = 0x80 | ((g >> 18) & 0x3f);
+        txt[2] = 0x80 | ((g >> 12) & 0x3f);
+        txt[3] = 0x80 | ((g >> 6 ) & 0x3f);
+        txt[4] = 0x80 | ((g      ) & 0x3f);
+        txt[5] = 0;
+     }
+   else if (g < (1 << (1 + 6 + 6 + 6 + 6 + 6)))
+     { // 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
+        txt[0] = 0xfc | ((g >> 30) & 0x01);
+        txt[1] = 0x80 | ((g >> 24) & 0x3f);
+        txt[2] = 0x80 | ((g >> 18) & 0x3f);
+        txt[3] = 0x80 | ((g >> 12) & 0x3f);
+        txt[4] = 0x80 | ((g >> 6 ) & 0x3f);
+        txt[5] = 0x80 | ((g      ) & 0x3f);
+        txt[6]  = 0;
+     }
+   else
+     { // error - cant encode this in utf8
+        txt[0] = 0;
+     }
+}
+
diff --git a/src/bin/utf8.h b/src/bin/utf8.h
new file mode 100644 (file)
index 0000000..0ac231e
--- /dev/null
@@ -0,0 +1,2 @@
+void glyph_to_utf8(int g, char *txt);
+    
diff --git a/src/bin/win.c b/src/bin/win.c
new file mode 100644 (file)
index 0000000..20334de
--- /dev/null
@@ -0,0 +1,24 @@
+#include <Elementary.h>
+#include "win.h"
+#include "config.h"
+
+Evas_Object *
+tg_win_add(void)
+{
+   Evas_Object *win, *o;
+   char buf[4096];
+   
+   win = elm_win_add(NULL, "main", ELM_WIN_BASIC);
+   elm_win_autodel_set(win, EINA_TRUE);
+   
+   elm_win_title_set(win, "Terminology");
+   elm_win_icon_name_set(win, "Terminology");
+   
+   o = evas_object_image_add(evas_object_evas_get(win));
+   snprintf(buf, sizeof(buf), "%s/icons/terminology.png",
+            elm_app_data_dir_get());
+   evas_object_image_file_set(o, buf, NULL);
+   elm_win_icon_object_set(win, o);
+   
+   return win;
+}
diff --git a/src/bin/win.h b/src/bin/win.h
new file mode 100644 (file)
index 0000000..0009ed6
--- /dev/null
@@ -0,0 +1 @@
+Evas_Object *tg_win_add(void);