├── src ├── Makefile.am ├── term.h └── term.c ├── .gitignore ├── sterm.conf.example ├── Makefile.am ├── configure.ac ├── README.md ├── get-version ├── autogen.sh └── m4 ├── ax_ld_check_flag.m4 └── ax_cflags_gcc_option.m4 /src/Makefile.am: -------------------------------------------------------------------------------- 1 | bin_PROGRAMS = term 2 | 3 | term_SOURCES = term.h term.c 4 | term_CFLAGS = @GTK_CFLAGS@ @VTE_CFLAGS@ 5 | term_LDFLAGS = @GTK_LIBS@ @VTE_LIBS@ 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.o 3 | *.lo 4 | *.a 5 | *.la 6 | /build*/ 7 | 8 | /ChangeLog 9 | /Makefile 10 | /config.h 11 | /config.log 12 | /config.status 13 | /libltdl/ 14 | /libtool 15 | /src/.deps/ 16 | /src/Makefile 17 | /src/term 18 | stamp-h1 19 | # autotools stuff 20 | /m4/lt*.m4 21 | /m4/libtool.m4 22 | /aclocal.m4 23 | /ltmain.sh 24 | /install-sh 25 | /config.guess 26 | /config.h.in 27 | /config.sub 28 | /autom4te.cache/ 29 | /compile 30 | /configure 31 | /depcomp 32 | /missing 33 | /test-driver 34 | 35 | # automake 36 | /ar-lib 37 | Makefile.in 38 | 39 | # cscope and other tags 40 | /cscope.* 41 | /GPATH 42 | /GRTAGS 43 | /GSYMS 44 | /GTAGS 45 | -------------------------------------------------------------------------------- /sterm.conf.example: -------------------------------------------------------------------------------- 1 | [main] 2 | WordChars=-A-Za-z0-9:./?%&#_=+@~" 3 | Themes=SolarizedDark;SolarizedLight 4 | 5 | [SolarizedDark] 6 | Font=Terminus 12 7 | Opacity=1.0 8 | Bold=false 9 | Cursor=#0f0f49499999 10 | Foreground=#838394949696 11 | Background=#00002b2b3636 12 | Palette=#070736364242;#dcdc32322f2f;#858599990000;#b5b589890000;#26268b8bd2d2;#d3d336368282;#2a2aa1a19898;#eeeee8e8d5d5;#00002b2b3636;#cbcb4b4b1616;#58586e6e7575;#65657b7b8383;#838394949696;#6c6c7171c4c4;#9393a1a1a1a1;#fdfdf6f6e3e3 13 | 14 | [SolarizedLight] 15 | Font=Terminus 12 16 | Opacity=1.0 17 | Bold=false 18 | Cursor=#586e75 19 | Foreground=#657b83 20 | Background=#fdf6e3 21 | Palette=#eee8d5;#dc322f;#859900;#b58900;#268bd2;#d33682;#2aa198;#073642;#fdf6e3;#cb4b16;#93a1a1;#839496;#657b83;#6c71c4;#586e75;#002b36 22 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | ACLOCAL_AMFLAGS = -I m4 2 | 3 | SUBDIRS = src 4 | EXTRA_DIST = get-version autogen.sh 5 | DISTCLEANFILES = ChangeLog 6 | dist_doc_DATA = README.md 7 | doc_DATA = ChangeLog 8 | 9 | # Build changelog from git history 10 | .PHONY: ChangeLog 11 | ChangeLog: 12 | $(AM_V_GEN)if test -d $(top_srcdir)/.git; then \ 13 | prev=$$(git describe --tags --always --match '[0-9]*' 2> /dev/null) ; \ 14 | for tag in $$(git tag | $(EGREP) '^[0-9]+(\.[0-9]+){1,}$$' | sort -rn); do \ 15 | if [ x"$$prev" = x ]; then prev=$$tag ; fi ; \ 16 | if [ x"$$prev" = x"$$tag" ]; then continue; fi ; \ 17 | echo "$$prev [$$(git log $$prev -1 --pretty=format:'%ai')]:" ; \ 18 | echo "" ; \ 19 | git log --pretty=' - [%h] %s (%an)' $$tag..$$prev ; \ 20 | echo "" ; \ 21 | prev=$$tag ; \ 22 | done > $@ ; \ 23 | else \ 24 | touch $@ ; \ 25 | fi 26 | 27 | dist-hook: 28 | echo $(VERSION) > $(distdir)/.dist-version -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | # -*- Autoconf -*- 2 | AC_PREREQ([2.64]) 3 | 4 | AC_INIT([sterm], 5 | [m4_esyscmd_s([./get-version])], 6 | [bernat@luffy.cx]) 7 | AC_CONFIG_SRCDIR([src/term.c]) 8 | AC_CONFIG_HEADER([config.h]) 9 | AC_CONFIG_FILES([Makefile src/Makefile]) 10 | AC_CONFIG_MACRO_DIR([m4]) 11 | AM_INIT_AUTOMAKE([foreign -Wall -Werror tar-ustar]) 12 | AM_MAINTAINER_MODE 13 | m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES(yes)]) 14 | m4_pattern_allow([AM_PROG_AR]) 15 | AM_PROG_AR 16 | 17 | # Configure libtool 18 | LT_INIT 19 | 20 | ####################### 21 | ### Checks 22 | 23 | # Checks for programs. 24 | AC_PROG_CC 25 | AC_PROG_CC_C99 26 | AC_PROG_CXX 27 | AM_PROG_CC_C_O 28 | AC_PROG_LIBTOOL 29 | AC_PROG_LN_S 30 | AC_PROG_EGREP 31 | 32 | # Check some compiler flags 33 | AX_CFLAGS_GCC_OPTION([-fdiagnostics-show-option]) 34 | AX_CFLAGS_GCC_OPTION([-pipe]) 35 | AX_CFLAGS_GCC_OPTION([-Wall]) 36 | AX_CFLAGS_GCC_OPTION([-W]) 37 | AX_CFLAGS_GCC_OPTION([-Wextra]) 38 | AX_CFLAGS_GCC_OPTION([-Wformat]) 39 | AX_CFLAGS_GCC_OPTION([-Wformat-security]) 40 | AX_CFLAGS_GCC_OPTION([-Wfatal-errors]) 41 | AX_CFLAGS_GCC_OPTION([-Wcast-align]) 42 | AX_CFLAGS_GCC_OPTION([-Winline]) 43 | AX_CFLAGS_GCC_OPTION([-fstack-protector]) 44 | AX_CFLAGS_GCC_OPTION([-D_FORTIFY_SOURCE=2]) 45 | AX_CFLAGS_GCC_OPTION([-Wno-unused-parameter]) 46 | AX_CFLAGS_GCC_OPTION([-Wno-missing-field-initializers]) 47 | AX_LDFLAGS_OPTION([-Wl,-z,relro]) 48 | AX_LDFLAGS_OPTION([-Wl,-z,now]) 49 | 50 | AC_CACHE_SAVE 51 | 52 | PKG_CHECK_MODULES([GTK], [gtk+-3.0 gdk-3.0]) 53 | PKG_CHECK_MODULES([VTE], [vte-2.90]) 54 | 55 | AC_CACHE_SAVE 56 | 57 | AC_OUTPUT 58 | 59 | cat < 6 | # 7 | # Redistribution and use in source and binary forms, with or without 8 | # modification, are permitted provided that the following conditions 9 | # are met: 10 | # 1. Redistributions of source code must retain the above copyright 11 | # notice, this list of conditions and the following disclaimer. 12 | # 2. Redistributions in binary form must reproduce the above copyright 13 | # notice, this list of conditions and the following disclaimer in the 14 | # documentation and/or other materials provided with the distribution. 15 | # 3. The name of the author may not be used to endorse or promote products 16 | # derived from this software without specific prior written permission. 17 | # 18 | # THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 19 | # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 20 | # AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 21 | # THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 22 | # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 23 | # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 24 | # OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 25 | # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 26 | # OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 27 | # ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | 29 | if [ -f .dist-version ]; then 30 | # Get the version from the file distributed in the tarball. 31 | version=$(cat .dist-version) 32 | elif [ -d .git ]; then 33 | # Ger the version from the git repository. 34 | version=$(git describe --tags --always --match [0-9]* 2> /dev/null) 35 | 36 | # Check if we are on a dirty checkout. 37 | git update-index --refresh -q >/dev/null 38 | dirty=$(git diff-index --name-only HEAD 2>/dev/null) 39 | if [ -n "$dirty" ]; then 40 | version="$version-dirty" 41 | fi 42 | else 43 | date +%F 44 | fi 45 | 46 | # Use printf to avoid the trailing new line that m4_esyscmd would not handle. 47 | printf "$version" -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | chmod +x $0 6 | chmod +x ./get-version 7 | 8 | [ ! -f .gitmodules ] || { 9 | echo "autogen.sh: updating git submodules" 10 | git submodule init 11 | git submodule update 12 | } 13 | 14 | case "$(uname)" in 15 | Darwin) 16 | LIBTOOLIZE=${LIBTOOLIZE:-glibtoolize} 17 | ;; 18 | *) 19 | LIBTOOLIZE=${LIBTOOLIZE:-libtoolize} 20 | ;; 21 | esac 22 | AUTORECONF=${AUTORECONF:-autoreconf} 23 | ACLOCAL=${ACLOCAL:-aclocal} 24 | AUTOCONF=${AUTOCONF:-autoconf} 25 | AUTOHEADER=${AUTOHEADER:-autoheader} 26 | AUTOMAKE=${AUTOMAKE:-automake} 27 | 28 | # Check we have all tools installed 29 | check_command() { 30 | command -v "${1}" > /dev/null 2>&1 || { 31 | >&2 echo "autogen.sh: could not find \`$1'. \`$1' is required to run autogen.sh." 32 | exit 1 33 | } 34 | } 35 | check_command "$LIBTOOLIZE" 36 | check_command "$AUTORECONF" 37 | check_command "$ACLOCAL" 38 | check_command "$AUTOCONF" 39 | check_command "$AUTOHEADER" 40 | check_command "$AUTOMAKE" 41 | 42 | # Absence of pkg-config or misconfiguration can make some odd error 43 | # messages, we check if it is installed correctly. See: 44 | # https://blogs.oracle.com/mandy/entry/autoconf_weirdness 45 | # 46 | # We cannot just check for pkg-config command, we need to check for 47 | # PKG_* macros. The pkg-config command can be defined in ./configure, 48 | # we cannot tell anything when not present. 49 | check_pkg_config() { 50 | grep -q '^AC_DEFUN.*PKG_CHECK_MODULES' aclocal.m4 || { 51 | cat <&2 52 | autogen.sh: could not find PKG_CHECK_MODULES macro. 53 | 54 | Either pkg-config is not installed on your system or 55 | \`pkg.m4' is missing or not found by aclocal. 56 | 57 | If \`pkg.m4' is installed at an unusual location, re-run 58 | \`autogen.sh' by setting \`ACLOCAL_FLAGS': 59 | 60 | ACLOCAL_FLAGS="-I /share/aclocal" ./autogen.sh 61 | 62 | EOF 63 | exit 1 64 | } 65 | } 66 | 67 | 68 | echo "autogen.sh: start libtoolize to get ltmain.sh" 69 | ${LIBTOOLIZE} --copy --force 70 | echo "autogen.sh: reconfigure with autoreconf" 71 | ${AUTORECONF} -vif -I m4 || { 72 | echo "autogen.sh: autoreconf has failed ($?), let's do it manually" 73 | for dir in $PWD *; do 74 | [ -d "$dir" ] || continue 75 | [ -f "$dir"/configure.ac ] || [ -f "$dir"/configure.in ] || continue 76 | echo "autogen.sh: configure `basename $dir`" 77 | (cd "$dir" && ${ACLOCAL} -I m4 ${ACLOCAL_FLAGS}) 78 | (cd "$dir" && check_pkg_config) 79 | (cd "$dir" && ${LIBTOOLIZE} --automake --copy --force) 80 | (cd "$dir" && ${ACLOCAL} -I m4 ${ACLOCAL_FLAGS}) 81 | (cd "$dir" && ${AUTOCONF} --force) 82 | (cd "$dir" && ${AUTOHEADER}) 83 | (cd "$dir" && ${AUTOMAKE} --add-missing --copy --force-missing) 84 | done 85 | } 86 | 87 | echo "autogen.sh: for the next step, run ./configure" 88 | 89 | exit 0 -------------------------------------------------------------------------------- /src/term.h: -------------------------------------------------------------------------------- 1 | /* -*- mode: c; c-file-style: "openbsd" -*- */ 2 | /* 3 | * Copyright (c) 2014 Vincent Bernat 4 | * Copyright (c) 2015 Pierre-Yves Ritschard 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #ifndef _BOOTSTRAP_H 20 | #define _BOOTSTRAP_H 21 | 22 | #if HAVE_CONFIG_H 23 | # include 24 | #endif 25 | 26 | #include 27 | 28 | #define TERM_WORD_CHARS "-A-Za-z0-9:./@?&%#_=+~" 29 | #define TERM_OPACITY 1.0 30 | #define TERM_FONT "Terminus 12" 31 | #define TERM_WORDCHARS_MAX 32 32 | #define TERM_THEME_NAMELEN 32 33 | #define TERM_THEMES_MAX 8 34 | #define TERM_THEME_PALETTE_MAX 16 35 | #define TERM_THEME_FONT_MAX 64 36 | #define TERM_CONFIG_PATH ".config/sterm/sterm.conf" 37 | #define TERM_CONFIG_DEFAULT ("[main]\n" \ 38 | "WordChars=-A-Za-z0-9:./?%&#_=+@~\n" \ 39 | "Themes=default\n" \ 40 | "[default]\n" \ 41 | "Font=DejaVu Sans Mono for Powerline 10\n" \ 42 | "Opacity=0.85\n" \ 43 | "Bold=true\n" \ 44 | "Cursor=#008800\n" \ 45 | "Foreground=#ffffff\n" \ 46 | "Background=#000000\n" \ 47 | "Palette=#111111;#d36265;#xaece91;" \ 48 | "#e7e18c;#5297cf;" \ 49 | "#963c59;#5E7175;#bebebe;" \ 50 | "#666666;#ef8171;#cfefb3;" \ 51 | "#fff796;#74b8ef;#b85e7b;#A3BABF;#ffffff\n") 52 | 53 | typedef struct { 54 | gchar name[TERM_THEME_NAMELEN]; 55 | GdkColor fg; 56 | GdkColor bg; 57 | GdkColor cursor; 58 | gboolean bold; 59 | gdouble opacity; 60 | gsize palette_size; 61 | GdkColor palette[TERM_THEME_PALETTE_MAX]; 62 | gchar font[TERM_THEME_FONT_MAX]; 63 | } TermTheme; 64 | 65 | typedef struct { 66 | gchar word_chars[TERM_WORDCHARS_MAX]; 67 | int theme_count; 68 | int theme_index; 69 | TermTheme themes[TERM_THEMES_MAX]; 70 | } TermConfig; 71 | 72 | #endif 73 | -------------------------------------------------------------------------------- /m4/ax_ld_check_flag.m4: -------------------------------------------------------------------------------- 1 | # =========================================================================== 2 | # http://www.gnu.org/software/autoconf-archive/ax_ld_check_flag.html 3 | # =========================================================================== 4 | # 5 | # SYNOPSIS 6 | # 7 | # AX_LD_CHECK_FLAG(FLAG-TO-CHECK,[PROLOGUE],[BODY],[ACTION-IF-SUCCESS],[ACTION-IF-FAILURE]) 8 | # 9 | # DESCRIPTION 10 | # 11 | # This macro tests if the C++ compiler supports the flag FLAG-TO-CHECK. If 12 | # successfull execute ACTION-IF-SUCCESS otherwise ACTION-IF-FAILURE. 13 | # PROLOGUE and BODY are optional and should be used as in AC_LANG_PROGRAM 14 | # macro. 15 | # 16 | # Example: 17 | # 18 | # AX_LD_CHECK_FLAG([-Wl,-L/usr/lib],[],[],[ 19 | # ... 20 | # ],[ 21 | # ... 22 | # ]) 23 | # 24 | # This code is inspired from KDE_CHECK_COMPILER_FLAG macro. Thanks to 25 | # Bogdan Drozdowski for testing and bug fixes. 26 | # 27 | # LICENSE 28 | # 29 | # Copyright (c) 2008 Francesco Salvestrini 30 | # 31 | # This program is free software; you can redistribute it and/or modify it 32 | # under the terms of the GNU General Public License as published by the 33 | # Free Software Foundation; either version 2 of the License, or (at your 34 | # option) any later version. 35 | # 36 | # This program is distributed in the hope that it will be useful, but 37 | # WITHOUT ANY WARRANTY; without even the implied warranty of 38 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 39 | # Public License for more details. 40 | # 41 | # You should have received a copy of the GNU General Public License along 42 | # with this program. If not, see . 43 | # 44 | # As a special exception, the respective Autoconf Macro's copyright owner 45 | # gives unlimited permission to copy, distribute and modify the configure 46 | # scripts that are the output of Autoconf when processing the Macro. You 47 | # need not follow the terms of the GNU General Public License when using 48 | # or distributing such scripts, even though portions of the text of the 49 | # Macro appear in them. The GNU General Public License (GPL) does govern 50 | # all other use of the material that constitutes the Autoconf Macro. 51 | # 52 | # This special exception to the GPL applies to versions of the Autoconf 53 | # Macro released by the Autoconf Archive. When you make and distribute a 54 | # modified version of the Autoconf Macro, you may extend this special 55 | # exception to the GPL to apply to your modified version as well. 56 | 57 | #serial 6 58 | 59 | AC_DEFUN([AX_LD_CHECK_FLAG],[ 60 | AC_PREREQ([2.61]) 61 | AC_REQUIRE([AC_PROG_CXX]) 62 | AC_REQUIRE([AC_PROG_SED]) 63 | 64 | flag=`echo "$1" | $SED 'y% .=/+-(){}<>:*,%_______________%'` 65 | 66 | AC_CACHE_CHECK([whether the linker accepts the $1 flag], 67 | [ax_cv_ld_check_flag_$flag],[ 68 | 69 | #AC_LANG_PUSH([C]) 70 | 71 | save_LDFLAGS="$LDFLAGS" 72 | LDFLAGS="$LDFLAGS $1" 73 | AC_LINK_IFELSE([ 74 | AC_LANG_PROGRAM([$2],[$3]) 75 | ],[ 76 | eval "ax_cv_ld_check_flag_$flag=yes" 77 | ],[ 78 | eval "ax_cv_ld_check_flag_$flag=no" 79 | ]) 80 | 81 | LDFLAGS="$save_LDFLAGS" 82 | 83 | #AC_LANG_POP 84 | 85 | ]) 86 | 87 | AS_IF([eval "test \"`echo '$ax_cv_ld_check_flag_'$flag`\" = yes"],[ 88 | : 89 | $4 90 | ],[ 91 | : 92 | $5 93 | ]) 94 | ]) 95 | 96 | AC_DEFUN([AX_LDFLAGS_OPTION],[ 97 | AX_LD_CHECK_FLAG([$1],[],[],[LDFLAGS="$LDFLAGS $1"])]) -------------------------------------------------------------------------------- /m4/ax_cflags_gcc_option.m4: -------------------------------------------------------------------------------- 1 | # =========================================================================== 2 | # http://autoconf-archive.cryp.to/ax_cflags_gcc_option.html 3 | # =========================================================================== 4 | # 5 | # SYNOPSIS 6 | # 7 | # AX_CFLAGS_GCC_OPTION (optionflag [,[shellvar][,[A][,[NA]]]) 8 | # 9 | # DESCRIPTION 10 | # 11 | # AX_CFLAGS_GCC_OPTION(-fvomit-frame) would show a message as like 12 | # "checking CFLAGS for gcc -fvomit-frame ... yes" and adds the optionflag 13 | # to CFLAGS if it is understood. You can override the shellvar-default of 14 | # CFLAGS of course. The order of arguments stems from the explicit macros 15 | # like AX_CFLAGS_WARN_ALL. 16 | # 17 | # The cousin AX_CXXFLAGS_GCC_OPTION would check for an option to add to 18 | # CXXFLAGS - and it uses the autoconf setup for C++ instead of C (since it 19 | # is possible to use different compilers for C and C++). 20 | # 21 | # The macro is a lot simpler than any special AX_CFLAGS_* macro (or 22 | # ac_cxx_rtti.m4 macro) but allows to check for arbitrary options. 23 | # However, if you use this macro in a few places, it would be great if you 24 | # would make up a new function-macro and submit it to the ac-archive. 25 | # 26 | # - $1 option-to-check-for : required ("-option" as non-value) 27 | # - $2 shell-variable-to-add-to : CFLAGS (or CXXFLAGS in the other case) 28 | # - $3 action-if-found : add value to shellvariable 29 | # - $4 action-if-not-found : nothing 30 | # 31 | # Note: in earlier versions, $1-$2 were swapped. We try to detect the 32 | # situation and accept a $2=~/-/ as being the old option-to-check-for. 33 | # 34 | # There are other variants that emerged from the original macro variant 35 | # which did just test an option to be possibly added. However, some 36 | # compilers accept an option silently, or possibly for just another option 37 | # that was not intended. Therefore, we have to do a generic test for a 38 | # compiler family. For gcc we check "-pedantic" being accepted which is 39 | # also understood by compilers who just want to be compatible with gcc 40 | # even when not being made from gcc sources. 41 | # 42 | # See also: AX_CFLAGS_SUN_OPTION, AX_CFLAGS_HPUX_OPTION, 43 | # AX_CFLAGS_AIX_OPTION, and AX_CFLAGS_IRIX_OPTION. 44 | # 45 | # LICENSE 46 | # 47 | # Copyright (c) 2008 Guido U. Draheim 48 | # 49 | # This program is free software; you can redistribute it and/or modify it 50 | # under the terms of the GNU General Public License as published by the 51 | # Free Software Foundation; either version 2 of the License, or (at your 52 | # option) any later version. 53 | # 54 | # This program is distributed in the hope that it will be useful, but 55 | # WITHOUT ANY WARRANTY; without even the implied warranty of 56 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 57 | # Public License for more details. 58 | # 59 | # You should have received a copy of the GNU General Public License along 60 | # with this program. If not, see . 61 | # 62 | # As a special exception, the respective Autoconf Macro's copyright owner 63 | # gives unlimited permission to copy, distribute and modify the configure 64 | # scripts that are the output of Autoconf when processing the Macro. You 65 | # need not follow the terms of the GNU General Public License when using 66 | # or distributing such scripts, even though portions of the text of the 67 | # Macro appear in them. The GNU General Public License (GPL) does govern 68 | # all other use of the material that constitutes the Autoconf Macro. 69 | # 70 | # This special exception to the GPL applies to versions of the Autoconf 71 | # Macro released by the Autoconf Archive. When you make and distribute a 72 | # modified version of the Autoconf Macro, you may extend this special 73 | # exception to the GPL to apply to your modified version as well. 74 | 75 | AC_DEFUN([AX_CFLAGS_GCC_OPTION_OLD], [dnl 76 | AS_VAR_PUSHDEF([FLAGS],[CFLAGS])dnl 77 | AS_VAR_PUSHDEF([VAR],[ac_cv_cflags_gcc_option_$2])dnl 78 | AC_CACHE_CHECK([m4_ifval($1,$1,FLAGS) for gcc m4_ifval($2,$2,-option)], 79 | VAR,[AS_VAR_SET([VAR], ["no, unknown"]) 80 | AC_LANG_SAVE 81 | AC_LANG_C 82 | ac_save_[]FLAGS="$[]FLAGS" 83 | for ac_arg dnl 84 | in "-pedantic -Werror % m4_ifval($2,$2,-option)" dnl GCC 85 | "-pedantic % m4_ifval($2,$2,-option) %% no, obsolete" dnl new GCC 86 | # 87 | do FLAGS="$ac_save_[]FLAGS "`echo $ac_arg | sed -e 's,%%.*,,' -e 's,%,,'` 88 | AC_TRY_COMPILE([],[return 0;], 89 | [AS_VAR_SET([VAR],[`echo $ac_arg | sed -e 's,.*% *,,'`]) ; break]) 90 | done 91 | FLAGS="$ac_save_[]FLAGS" 92 | AC_LANG_RESTORE 93 | ]) 94 | AS_VAR_COPY([ac_res], [VAR]) 95 | case ".${ac_res}" in 96 | .ok|.ok,*) m4_ifvaln($3,$3) ;; 97 | .|.no|.no,*) m4_ifvaln($4,$4) ;; 98 | *) m4_ifvaln($3,$3,[ 99 | if echo " $[]m4_ifval($1,$1,FLAGS) " | grep " ${ac_res} " 2>&1 >/dev/null 100 | then AC_RUN_LOG([: m4_ifval($1,$1,FLAGS) does contain ${ac_res}]) 101 | else AC_RUN_LOG([: m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) ${ac_res}"]) 102 | m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) ${ac_res}" 103 | fi ]) ;; 104 | esac 105 | AS_VAR_POPDEF([VAR])dnl 106 | AS_VAR_POPDEF([FLAGS])dnl 107 | ]) 108 | 109 | 110 | dnl the only difference - the LANG selection... and the default FLAGS 111 | 112 | AC_DEFUN([AX_CXXFLAGS_GCC_OPTION_OLD], [dnl 113 | AS_VAR_PUSHDEF([FLAGS],[CXXFLAGS])dnl 114 | AS_VAR_PUSHDEF([VAR],[ac_cv_cxxflags_gcc_option_$2])dnl 115 | AC_CACHE_CHECK([m4_ifval($1,$1,FLAGS) for gcc m4_ifval($2,$2,-option)], 116 | VAR,[AS_VAR_SET([VAR],["no, unknown"]) 117 | AC_LANG_SAVE 118 | AC_LANG_CPLUSPLUS 119 | ac_save_[]FLAGS="$[]FLAGS" 120 | for ac_arg dnl 121 | in "-pedantic -Werror % m4_ifval($2,$2,-option)" dnl GCC 122 | "-pedantic % m4_ifval($2,$2,-option) %% no, obsolete" dnl new GCC 123 | # 124 | do FLAGS="$ac_save_[]FLAGS "`echo $ac_arg | sed -e 's,%%.*,,' -e 's,%,,'` 125 | AC_TRY_COMPILE([],[return 0;], 126 | [AS_VAR_SET([VAR],[`echo $ac_arg | sed -e 's,.*% *,,'`]) ; break]) 127 | done 128 | FLAGS="$ac_save_[]FLAGS" 129 | AC_LANG_RESTORE 130 | ]) 131 | AS_VAR_COPY([ac_res], [VAR]) 132 | case ".${ac_res}" in 133 | .ok|.ok,*) m4_ifvaln($3,$3) ;; 134 | .|.no|.no,*) m4_ifvaln($4,$4) ;; 135 | *) m4_ifvaln($3,$3,[ 136 | if echo " $[]m4_ifval($1,$1,FLAGS) " | grep " ${VAR} " 2>&1 >/dev/null 137 | then AC_RUN_LOG([: m4_ifval($1,$1,FLAGS) does contain ${ac_res}]) 138 | else AC_RUN_LOG([: m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) ${ac_res}"]) 139 | m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) ${ac_res}" 140 | fi ]) ;; 141 | esac 142 | AS_VAR_POPDEF([VAR])dnl 143 | AS_VAR_POPDEF([FLAGS])dnl 144 | ]) 145 | 146 | dnl ------------------------------------------------------------------------- 147 | 148 | AC_DEFUN([AX_CFLAGS_GCC_OPTION_NEW], [dnl 149 | AS_VAR_PUSHDEF([FLAGS],[CFLAGS])dnl 150 | AS_VAR_PUSHDEF([VAR],[ac_cv_cflags_gcc_option_$1])dnl 151 | AC_CACHE_CHECK([m4_ifval($2,$2,FLAGS) for gcc m4_ifval($1,$1,-option)], 152 | VAR,[AS_VAR_SET([VAR],["no, unknown"]) 153 | AC_LANG_SAVE 154 | AC_LANG_C 155 | ac_save_[]FLAGS="$[]FLAGS" 156 | for ac_arg dnl 157 | in "-pedantic -Werror % m4_ifval($1,$1,-option)" dnl GCC 158 | "-pedantic % m4_ifval($1,$1,-option) %% no, obsolete" dnl new GCC 159 | # 160 | do FLAGS="$ac_save_[]FLAGS "`echo $ac_arg | sed -e 's,%%.*,,' -e 's,%,,'` 161 | AC_TRY_COMPILE([],[return 0;], 162 | [AS_VAR_SET([VAR],[`echo $ac_arg | sed -e 's,.*% *,,'`]) ; break]) 163 | done 164 | FLAGS="$ac_save_[]FLAGS" 165 | AC_LANG_RESTORE 166 | ]) 167 | AS_VAR_COPY([ac_res], [VAR]) 168 | case ".${ac_res}" in 169 | .ok|.ok,*) m4_ifvaln($3,$3) ;; 170 | .|.no|.no,*) m4_ifvaln($4,$4) ;; 171 | *) m4_ifvaln($3,$3,[ 172 | if echo " $[]m4_ifval($2,$2,FLAGS) " | grep " ${ac_res} " 2>&1 >/dev/null 173 | then AC_RUN_LOG([: m4_ifval($2,$2,FLAGS) does contain ${ac_res}]) 174 | else AC_RUN_LOG([: m4_ifval($2,$2,FLAGS)="$m4_ifval($2,$2,FLAGS) ${ac_res}"]) 175 | m4_ifval($2,$2,FLAGS)="$m4_ifval($2,$2,FLAGS) ${ac_res}" 176 | fi ]) ;; 177 | esac 178 | AS_VAR_POPDEF([VAR])dnl 179 | AS_VAR_POPDEF([FLAGS])dnl 180 | ]) 181 | 182 | 183 | dnl the only difference - the LANG selection... and the default FLAGS 184 | 185 | AC_DEFUN([AX_CXXFLAGS_GCC_OPTION_NEW], [dnl 186 | AS_VAR_PUSHDEF([FLAGS],[CXXFLAGS])dnl 187 | AS_VAR_PUSHDEF([VAR],[ac_cv_cxxflags_gcc_option_$1])dnl 188 | AC_CACHE_CHECK([m4_ifval($2,$2,FLAGS) for gcc m4_ifval($1,$1,-option)], 189 | VAR,[AS_VAR_SET([VAR],["no, unknown"]) 190 | AC_LANG_SAVE 191 | AC_LANG_CPLUSPLUS 192 | ac_save_[]FLAGS="$[]FLAGS" 193 | for ac_arg dnl 194 | in "-pedantic -Werror % m4_ifval($1,$1,-option)" dnl GCC 195 | "-pedantic % m4_ifval($1,$1,-option) %% no, obsolete" dnl new GCC 196 | # 197 | do FLAGS="$ac_save_[]FLAGS "`echo $ac_arg | sed -e 's,%%.*,,' -e 's,%,,'` 198 | AC_TRY_COMPILE([],[return 0;], 199 | [AS_VAR_SET([VAR],[`echo $ac_arg | sed -e 's,.*% *,,'`]) ; break]) 200 | done 201 | FLAGS="$ac_save_[]FLAGS" 202 | AC_LANG_RESTORE 203 | ]) 204 | AS_VAR_COPY([ac_res], [VAR]) 205 | case ".${ac_res}" in 206 | .ok|.ok,*) m4_ifvaln($3,$3) ;; 207 | .|.no|.no,*) m4_ifvaln($4,$4) ;; 208 | *) m4_ifvaln($3,$3,[ 209 | if echo " $[]m4_ifval($2,$2,FLAGS) " | grep " ${ac_res} " 2>&1 >/dev/null 210 | then AC_RUN_LOG([: m4_ifval($2,$2,FLAGS) does contain ${ac_res}]) 211 | else AC_RUN_LOG([: m4_ifval($2,$2,FLAGS)="$m4_ifval($2,$2,FLAGS) ${ac_res}"]) 212 | m4_ifval($2,$2,FLAGS)="$m4_ifval($2,$2,FLAGS) ${ac_res}" 213 | fi ]) ;; 214 | esac 215 | AS_VAR_POPDEF([VAR])dnl 216 | AS_VAR_POPDEF([FLAGS])dnl 217 | ]) 218 | 219 | AC_DEFUN([AX_CFLAGS_GCC_OPTION],[ifelse(m4_bregexp([$2],[-]),-1, 220 | [AX_CFLAGS_GCC_OPTION_NEW($@)],[AX_CFLAGS_GCC_OPTION_OLD($@)])]) 221 | 222 | AC_DEFUN([AX_CXXFLAGS_GCC_OPTION],[ifelse(m4_bregexp([$2],[-]),-1, 223 | [AX_CXXFLAGS_GCC_OPTION_NEW($@)],[AX_CXXFLAGS_GCC_OPTION_OLD($@)])]) -------------------------------------------------------------------------------- /src/term.c: -------------------------------------------------------------------------------- 1 | /* -*- mode: c; c-file-style: "openbsd" -*- */ 2 | /* 3 | * Copyright (c) 2014 Vincent Bernat 4 | * Copyright (c) 2015 Pierre-Yves Ritschard 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include "term.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | GtkWidget *window, *terminal; 32 | TermConfig config; 33 | gchar *cmd = NULL; 34 | 35 | static void 36 | set_font_size(gint delta) 37 | { 38 | PangoFontDescription *descr; 39 | descr = pango_font_description_copy(vte_terminal_get_font(VTE_TERMINAL(terminal))); 40 | if (!descr) return; 41 | 42 | gint current = pango_font_description_get_size(descr); 43 | pango_font_description_set_size(descr, current + delta * PANGO_SCALE); 44 | vte_terminal_set_font(VTE_TERMINAL(terminal), descr); 45 | pango_font_description_free(descr); 46 | } 47 | 48 | static gboolean 49 | term_config_load_theme(GKeyFile *kf, gchar *grp, TermTheme *theme) 50 | { 51 | gsize len; 52 | gsize i; 53 | gchar *val; 54 | gchar **lval; 55 | 56 | theme->opacity = g_key_file_get_double(kf, grp, "Opacity", NULL); 57 | theme->bold = g_key_file_get_boolean(kf, grp, "Bold", NULL); 58 | 59 | #pragma GCC diagnostic push 60 | #pragma GCC diagnostic ignored "-Wdeprecated-declarations" 61 | 62 | if ((val = g_key_file_get_string(kf, grp, "Cursor", NULL)) == NULL) 63 | return FALSE; 64 | gdk_color_parse(val, &theme->cursor); 65 | g_free(val); 66 | 67 | if ((val = g_key_file_get_string(kf, grp, "Font", NULL)) == NULL) 68 | return FALSE; 69 | g_strlcpy(theme->font, val, sizeof(theme->font)); 70 | g_free(val); 71 | 72 | if ((val = g_key_file_get_string(kf, grp, "Foreground", NULL)) == NULL) 73 | return FALSE; 74 | gdk_color_parse(val, &theme->fg); 75 | g_free(val); 76 | 77 | if ((val = g_key_file_get_string(kf, grp, "Background", NULL)) == NULL) 78 | return FALSE; 79 | gdk_color_parse(val, &theme->bg); 80 | g_free(val); 81 | 82 | if ((lval = g_key_file_get_string_list(kf, grp, "Palette", 83 | &len, NULL)) == NULL) 84 | return FALSE; 85 | 86 | theme->palette_size = len; 87 | if (len > TERM_THEME_PALETTE_MAX) { 88 | g_free(lval); 89 | return FALSE; 90 | } 91 | 92 | for (i = 0; i < theme->palette_size; i++) { 93 | gdk_color_parse(lval[i], &theme->palette[i]); 94 | } 95 | g_free(lval); 96 | 97 | #pragma GCC diagnostic pop 98 | return TRUE; 99 | } 100 | 101 | static void 102 | term_config_load(void) 103 | { 104 | gchar *path; 105 | GKeyFile *kf; 106 | gboolean ret; 107 | gchar *grp; 108 | gchar *val; 109 | gchar **lval; 110 | gsize len; 111 | gsize i; 112 | 113 | kf = g_key_file_new(); 114 | path = g_strdup_printf("%s/%s", g_getenv("HOME")?:"", TERM_CONFIG_PATH); 115 | ret = g_key_file_load_from_file(kf, 116 | path, 117 | G_KEY_FILE_NONE, 118 | NULL); 119 | g_free(path); 120 | 121 | if (!ret) { 122 | /* 123 | * provide some sensible defaults 124 | */ 125 | g_key_file_load_from_data(kf, TERM_CONFIG_DEFAULT, 126 | strlen(TERM_CONFIG_DEFAULT), 127 | G_KEY_FILE_NONE, 128 | NULL); 129 | } 130 | 131 | grp = g_key_file_get_start_group(kf); 132 | 133 | if ((val = g_key_file_get_string(kf, grp, 134 | "WordChars", NULL)) == NULL) { 135 | g_strlcpy(config.word_chars, TERM_WORD_CHARS, 136 | sizeof(config.word_chars)); 137 | } else { 138 | g_strlcpy(config.word_chars, val, sizeof(config.word_chars)); 139 | } 140 | 141 | if ((lval = g_key_file_get_string_list(kf, grp, "Themes", 142 | &len, NULL)) == NULL || len <= 0) { 143 | config.theme_count = 0; 144 | return; 145 | } 146 | for (i = 0; i < len; i++) { 147 | TermTheme *theme; 148 | 149 | theme = &config.themes[config.theme_count]; 150 | if (term_config_load_theme(kf, lval[i], theme)) 151 | config.theme_count++; 152 | else 153 | bzero(theme, sizeof(*theme)); 154 | } 155 | } 156 | 157 | void 158 | term_theme_apply(gint index) 159 | { 160 | TermTheme *theme = &config.themes[index]; 161 | 162 | if (index >= config.theme_count) 163 | return; 164 | 165 | vte_terminal_set_scrollback_lines(VTE_TERMINAL(terminal), 8192); 166 | vte_terminal_set_scroll_on_output(VTE_TERMINAL(terminal), FALSE); 167 | vte_terminal_set_scroll_on_keystroke(VTE_TERMINAL(terminal), TRUE); 168 | vte_terminal_set_rewrap_on_resize(VTE_TERMINAL(terminal), TRUE); 169 | 170 | vte_terminal_set_colors(VTE_TERMINAL(terminal), &theme->fg, &theme->bg, 171 | theme->palette, theme->palette_size); 172 | 173 | #pragma GCC diagnostic push 174 | #pragma GCC diagnostic ignored "-Wdeprecated-declarations" 175 | vte_terminal_set_opacity(VTE_TERMINAL(terminal), theme->opacity * 65535); 176 | #pragma GCC diagnostic pop 177 | 178 | vte_terminal_set_color_cursor(VTE_TERMINAL(terminal), &theme->cursor); 179 | vte_terminal_set_cursor_blink_mode(VTE_TERMINAL(terminal), 180 | VTE_CURSOR_BLINK_OFF); 181 | vte_terminal_set_allow_bold(VTE_TERMINAL(terminal), theme->bold); 182 | vte_terminal_set_font_from_string(VTE_TERMINAL(terminal), theme->font); 183 | set_font_size(0); 184 | 185 | vte_terminal_set_audible_bell(VTE_TERMINAL(terminal), FALSE); 186 | vte_terminal_set_visible_bell(VTE_TERMINAL(terminal), FALSE); 187 | } 188 | 189 | void 190 | term_theme_cycle() 191 | { 192 | gint next_theme = (config.theme_index + 1) % config.theme_count; 193 | 194 | if (config.theme_count <= 0) 195 | return; 196 | term_theme_apply(next_theme); 197 | config.theme_index = next_theme; 198 | } 199 | 200 | static gboolean 201 | on_dpi_changed(GtkSettings *settings, 202 | GParamSpec *pspec, 203 | gpointer user_data) 204 | { 205 | set_font_size(0); 206 | return TRUE; 207 | } 208 | 209 | static gboolean 210 | on_char_size_changed(GtkWidget *terminal, guint width, guint height, gpointer user_data) 211 | { 212 | set_font_size(0); 213 | return TRUE; 214 | } 215 | 216 | static gboolean 217 | on_title_changed(GtkWidget *terminal, gpointer user_data) 218 | { 219 | gtk_window_set_title(GTK_WINDOW(window), 220 | vte_terminal_get_window_title(VTE_TERMINAL(terminal))?:PACKAGE_NAME); 221 | return TRUE; 222 | } 223 | 224 | static gboolean 225 | on_key_press(GtkWidget *terminal, GdkEventKey *event) 226 | { 227 | if (event->state & GDK_CONTROL_MASK) { 228 | switch (event->keyval) { 229 | case GDK_plus: 230 | set_font_size(1); 231 | return TRUE; 232 | case GDK_minus: 233 | set_font_size(-1); 234 | return TRUE; 235 | case GDK_equal: 236 | set_font_size(0); 237 | return TRUE; 238 | case GDK_percent: 239 | term_theme_cycle(); 240 | return TRUE; 241 | } 242 | } 243 | return FALSE; 244 | } 245 | 246 | static gchar** 247 | get_child_environment(void) 248 | { 249 | guint n; 250 | gchar **env, **result, **p; 251 | const gchar *value; 252 | 253 | /* Copy the current environment */ 254 | env = g_listenv(); 255 | n = g_strv_length (env); 256 | result = g_new (gchar *, n + 2); 257 | for (n = 0, p = env; *p != NULL; ++p) { 258 | if (g_strcmp0(*p, "COLORTERM") == 0) continue; 259 | value = g_getenv (*p); 260 | if (G_LIKELY(value != NULL)) 261 | result[n++] = g_strconcat (*p, "=", value, NULL); 262 | } 263 | g_strfreev(env); 264 | 265 | /* Setup COLORTERM */ 266 | result[n++] = g_strdup_printf("COLORTERM=%s", PACKAGE_NAME); 267 | result[n] = NULL; 268 | return result; 269 | } 270 | 271 | int 272 | main(int argc, char *argv[]) 273 | { 274 | int c; 275 | 276 | while ((c = getopt(argc, argv, "e:")) != -1) { 277 | switch (c) { 278 | case 'e': 279 | cmd = g_strdup(optarg); 280 | break; 281 | } 282 | } 283 | /* Initialise GTK and the widgets */ 284 | gtk_init(&argc, &argv); 285 | 286 | /* load configuration */ 287 | bzero(&config, sizeof(config)); 288 | term_config_load(); 289 | window = gtk_window_new(GTK_WINDOW_TOPLEVEL); 290 | terminal = vte_terminal_new(); 291 | gtk_window_set_title(GTK_WINDOW(window), PACKAGE_NAME); 292 | gtk_container_add(GTK_CONTAINER(window), terminal); 293 | gtk_widget_set_visual(window, gdk_screen_get_rgba_visual(gtk_widget_get_screen(window))); 294 | gtk_widget_show_all(window); 295 | gtk_window_set_focus(GTK_WINDOW(window), terminal); 296 | 297 | /* Connect some signals */ 298 | g_signal_connect(window, "delete-event", gtk_main_quit, NULL); 299 | g_signal_connect(terminal, "child-exited", gtk_main_quit, NULL); 300 | g_signal_connect(terminal, "window-title-changed", G_CALLBACK(on_title_changed), NULL); 301 | g_signal_connect(terminal, "key-press-event", G_CALLBACK(on_key_press), NULL); 302 | g_signal_connect(terminal, "char-size-changed", G_CALLBACK(on_char_size_changed), NULL); 303 | g_signal_connect(gtk_settings_get_default(), "notify::gtk-xft-dpi", 304 | G_CALLBACK(on_dpi_changed), NULL); 305 | 306 | /* Configure terminal */ 307 | vte_terminal_set_word_chars(VTE_TERMINAL(terminal), config.word_chars); 308 | term_theme_apply(0); 309 | 310 | 311 | /* Start a new shell */ 312 | gchar **env; 313 | gchar **fork_cmd; 314 | env = get_child_environment(); 315 | if (cmd) { 316 | fork_cmd = (gchar *[]){ "/bin/sh", "-c", cmd, NULL }; 317 | } else { 318 | fork_cmd = (gchar *[]){ g_strdup(g_getenv("SHELL")), NULL }; 319 | } 320 | vte_terminal_fork_command_full(VTE_TERMINAL (terminal), 321 | VTE_PTY_DEFAULT, 322 | NULL, /* working directory */ 323 | fork_cmd, 324 | env, /* envv */ 325 | 0, /* spawn flags */ 326 | NULL, NULL, /* child setup */ 327 | NULL, /* child pid */ 328 | NULL); 329 | g_strfreev(env); 330 | 331 | /* Pack widgets and start the terminal */ 332 | gtk_main(); 333 | return FALSE; 334 | } 335 | --------------------------------------------------------------------------------