--- /dev/null
+Carsten Haitzler (Rasterman) <raster@rasterman.com>
--- /dev/null
+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.
--- /dev/null
+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
+
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+#!/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
--- /dev/null
+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
--- /dev/null
+MAINTAINERCLEANFILES = Makefile.in
+SUBDIRS = desktop icons images fonts themes
+
--- /dev/null
+MAINTAINERCLEANFILES = Makefile.in
+filesdir = $(datadir)/applications
+files_DATA = \
+terminology.desktop
+
+EXTRA_DIST = $(files_DATA)
--- /dev/null
+[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
--- /dev/null
+MAINTAINERCLEANFILES = Makefile.in
+filesdir = $(pkgdatadir)/fonts
+files_DATA = \
+nex6x10.pcf
+
+EXTRA_DIST = $(files_DATA)
--- /dev/null
+MAINTAINERCLEANFILES = Makefile.in
+filesdir = $(datadir)/icons
+files_DATA = \
+terminology.png
+
+EXTRA_DIST = $(files_DATA)
--- /dev/null
+MAINTAINERCLEANFILES = Makefile.in
+filesdir = $(pkgdatadir)/images
+files_DATA =
+
+EXTRA_DIST = $(files_DATA)
--- /dev/null
+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
--- /dev/null
+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";
+ }
+ }
+ }
+ }
+}
--- /dev/null
+MAINTAINERCLEANFILES = Makefile.in
+EXTRA_DIST = \
+bg_bevel.png \
+bg_shine.png
--- /dev/null
+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)
+
+])
--- /dev/null
+MAINTAINERCLEANFILES = Makefile.in
+SUBDIRS = bin
--- /dev/null
+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
--- /dev/null
+#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 },
+};
--- /dev/null
+typedef struct _Color Color;
+
+struct _Color
+{
+ unsigned char r, g, b, a;
+};
+
+extern const Color colors[2][11];
+extern const Color colors256[256];
--- /dev/null
+#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)
+{
+}
--- /dev/null
+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);
+
--- /dev/null
+#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));
+ }
+}
--- /dev/null
+void keyin_handle(Termpty *ty, Evas_Event_Key_Down *ev);
+
--- /dev/null
+#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()
--- /dev/null
+#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;
+}
--- /dev/null
+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);
--- /dev/null
+#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);
+}
--- /dev/null
+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);
+
--- /dev/null
+#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;
+ }
+}
+
--- /dev/null
+void glyph_to_utf8(int g, char *txt);
+
--- /dev/null
+#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;
+}
--- /dev/null
+Evas_Object *tg_win_add(void);