summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.circleci/config.yml121
-rw-r--r--.github/FUNDING.yml1
-rw-r--r--ChangeLog26
-rw-r--r--ChangeLog.theme5
-rw-r--r--DESIGN.md2
-rw-r--r--NEWS35
-rw-r--r--README.md5
-rw-r--r--data/desktop/meson.build14
-rw-r--r--data/desktop/terminology.desktop.in (renamed from data/desktop/terminology.desktop)3
-rw-r--r--data/themes/default.edc269
-rw-r--r--data/themes/mild.edc272
-rw-r--r--man/terminology-helpers.12
-rw-r--r--man/terminology.12
-rw-r--r--meson.build8
-rw-r--r--snap/snapcraft.yaml174
-rw-r--r--src/bin/backlog.c226
-rw-r--r--src/bin/backlog.h30
-rw-r--r--src/bin/config.c30
-rw-r--r--src/bin/controls.c2
-rw-r--r--src/bin/ipc.c33
-rw-r--r--src/bin/ipc.h48
-rw-r--r--src/bin/main.c870
-rw-r--r--src/bin/main.h2
-rw-r--r--src/bin/media.c5
-rw-r--r--src/bin/meson.build6
-rw-r--r--src/bin/miniview.c1
-rw-r--r--src/bin/options_behavior.c27
-rw-r--r--src/bin/sb.c13
-rw-r--r--src/bin/termcmd.c18
-rw-r--r--src/bin/termio.c55
-rw-r--r--src/bin/termiointernals.c141
-rw-r--r--src/bin/termiolink.c2
-rw-r--r--src/bin/termpty.c347
-rw-r--r--src/bin/termpty.h20
-rw-r--r--src/bin/termptyesc.c401
-rw-r--r--src/bin/termptyops.c28
-rw-r--r--src/bin/termptysave.c91
-rw-r--r--src/bin/termptysave.h12
-rw-r--r--src/bin/tyalpha.c3
-rw-r--r--src/bin/tybg.c6
-rw-r--r--src/bin/tycat.c12
-rw-r--r--src/bin/tycommon.c24
-rw-r--r--src/bin/tycommon.h1
-rw-r--r--src/bin/tyfuzz.c17
-rw-r--r--src/bin/tyls.c3
-rw-r--r--src/bin/typop.c3
-rw-r--r--src/bin/tyq.c3
-rw-r--r--src/bin/tysend.c12
-rw-r--r--src/bin/win.c175
-rwxr-xr-xtests/osc-invalid.sh33
-rwxr-xr-xtests/selection_empty_lines.sh42
-rwxr-xr-xtests/selection_with_tabs.sh33
-rw-r--r--tests/tests.results20
-rwxr-xr-xtests/title_icon_stack_default.sh34
-rwxr-xr-xtests/title_icon_stack_simple.sh30
-rwxr-xr-xtests/title_icon_stack_unset.sh30
56 files changed, 2633 insertions, 1195 deletions
diff --git a/.circleci/config.yml b/.circleci/config.yml
index 74174e0..d61ea66 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -20,52 +20,41 @@ jobs:
20 key: checkout-{{ .Environment.CIRCLE_SHA1 }} 20 key: checkout-{{ .Environment.CIRCLE_SHA1 }}
21 paths: 21 paths:
22 - /terminology 22 - /terminology
23 23 build_minimal_gcc_efl-1.20:
24 build_full_clang_efl-1.22:
25 docker: 24 docker:
26 - image: borisfaure/terminology-ci:latest 25 - image: borisfaure/terminology-ci:latest
27 environment:
28 - CC: clang
29 steps: 26 steps:
30 - restore_cache: 27 - restore_cache:
31 key: checkout-{{ .Environment.CIRCLE_SHA1 }} 28 key: checkout-{{ .Environment.CIRCLE_SHA1 }}
32 - run: 29 - run:
33 name: Install EFL 30 name: Install EFL
34 command: apk add /pkg/efl-1.22.6-r0.apk /pkg/efl-dev-1.22.6-r0.apk 31 command: apk add /pkg/efl-1.20.7-r0.apk /pkg/efl-dev-1.20.7-r0.apk
35 - run: 32 - run:
36 name: Compile with Clang 33 name: Compile with GCC
37 command: | 34 command: |
38 cd /terminology 35 cd /terminology
39 meson -Dtests=true -Dfuzzing=true . build 36 meson . build
40 meson configure build 37 meson configure build
41 cd build 38 cd build
42 ninja -j4 39 ninja -j4
43 build_and_test_clang_ubsan_efl-1.22: 40 build_minimal_gcc_efl-1.21:
44 docker: 41 docker:
45 - image: borisfaure/terminology-ci:latest 42 - image: borisfaure/terminology-ci:latest
46 environment:
47 - CC: clang
48 - CFLAGS: -O0 -pipe -g -fno-omit-frame-pointer -fsanitize=undefined -fno-sanitize-recover=undefined
49 steps: 43 steps:
50 - restore_cache: 44 - restore_cache:
51 key: checkout-{{ .Environment.CIRCLE_SHA1 }} 45 key: checkout-{{ .Environment.CIRCLE_SHA1 }}
52 - run: 46 - run:
53 name: Install EFL 47 name: Install EFL
54 command: apk add /pkg/efl-1.22.6-r0.apk /pkg/efl-dev-1.22.6-r0.apk 48 command: apk add /pkg/efl-1.21.1-r0.apk /pkg/efl-dev-1.21.1-r0.apk
55 - run: 49 - run:
56 name: Compile with Clang 50 name: Compile with GCC
57 command: | 51 command: |
58 cd /terminology 52 cd /terminology
59 meson -Dtests=true . build 53 meson . build
60 meson configure build 54 meson configure build
61 cd build 55 cd build
62 ninja -j4 56 ninja -j4
63 - run: 57 build_minimal_gcc_efl-1.22:
64 name: Launch tests
65 command: |
66 cd /terminology
67 tests/run_tests.sh -v -t build/src/bin/tytest -r tests/tests.results -d tests/
68 build_full_gcc_efl-1.22:
69 docker: 58 docker:
70 - image: borisfaure/terminology-ci:latest 59 - image: borisfaure/terminology-ci:latest
71 steps: 60 steps:
@@ -76,19 +65,13 @@ jobs:
76 command: apk add /pkg/efl-1.22.6-r0.apk /pkg/efl-dev-1.22.6-r0.apk 65 command: apk add /pkg/efl-1.22.6-r0.apk /pkg/efl-dev-1.22.6-r0.apk
77 - run: 66 - run:
78 name: Compile with GCC 67 name: Compile with GCC
79 environment:
80 CFLAGS: -O0 -g
81 command: | 68 command: |
82 cd /terminology 69 cd /terminology
83 meson -Dtests=true -Dfuzzing=true -Db_coverage=true . build 70 meson . build
84 meson configure build 71 meson configure build
85 cd build 72 cd build
86 ninja -j4 73 ninja -j4
87 - save_cache: 74 build_minimal_gcc_efl-1.23:
88 key: build_full_gcc-efl-1.22-{{ .Environment.CIRCLE_SHA1 }}
89 paths:
90 - /terminology
91 build_minimal_gcc_efl-1.21:
92 docker: 75 docker:
93 - image: borisfaure/terminology-ci:latest 76 - image: borisfaure/terminology-ci:latest
94 steps: 77 steps:
@@ -96,7 +79,7 @@ jobs:
96 key: checkout-{{ .Environment.CIRCLE_SHA1 }} 79 key: checkout-{{ .Environment.CIRCLE_SHA1 }}
97 - run: 80 - run:
98 name: Install EFL 81 name: Install EFL
99 command: apk add /pkg/efl-1.21.1-r0.apk /pkg/efl-dev-1.21.1-r0.apk 82 command: apk add /pkg/efl-1.23.1-r0.apk /pkg/efl-dev-1.23.1-r0.apk
100 - run: 83 - run:
101 name: Compile with GCC 84 name: Compile with GCC
102 command: | 85 command: |
@@ -105,7 +88,7 @@ jobs:
105 meson configure build 88 meson configure build
106 cd build 89 cd build
107 ninja -j4 90 ninja -j4
108 build_minimal_gcc_efl-1.20: 91 build_full_gcc_efl_latest:
109 docker: 92 docker:
110 - image: borisfaure/terminology-ci:latest 93 - image: borisfaure/terminology-ci:latest
111 steps: 94 steps:
@@ -113,24 +96,30 @@ jobs:
113 key: checkout-{{ .Environment.CIRCLE_SHA1 }} 96 key: checkout-{{ .Environment.CIRCLE_SHA1 }}
114 - run: 97 - run:
115 name: Install EFL 98 name: Install EFL
116 command: apk add /pkg/efl-1.20.7-r0.apk /pkg/efl-dev-1.20.7-r0.apk 99 command: apk add /pkg/efl-latest.apk /pkg/efl-dev-latest.apk
117 - run: 100 - run:
118 name: Compile with GCC 101 name: Compile with GCC
102 environment:
103 CFLAGS: -O0 -g
119 command: | 104 command: |
120 cd /terminology 105 cd /terminology
121 meson . build 106 meson -Dtests=true -Dfuzzing=true -Db_coverage=true . build
122 meson configure build 107 meson configure build
123 cd build 108 cd build
124 ninja -j4 109 ninja -j4
125 tests_gcc: 110 - save_cache:
111 key: build_full_gcc_efl_latest-{{ .Environment.CIRCLE_SHA1 }}
112 paths:
113 - /terminology
114 tests_gcc_efl_latest:
126 docker: 115 docker:
127 - image: borisfaure/terminology-ci:latest 116 - image: borisfaure/terminology-ci:latest
128 steps: 117 steps:
129 - restore_cache: 118 - restore_cache:
130 key: build_full_gcc-efl-1.22-{{ .Environment.CIRCLE_SHA1 }} 119 key: build_full_gcc_efl_latest-{{ .Environment.CIRCLE_SHA1 }}
131 - run: 120 - run:
132 name: Install EFL 121 name: Install EFL
133 command: apk add /pkg/efl-1.22.6-r0.apk /pkg/efl-dev-1.22.6-r0.apk 122 command: apk add /pkg/efl-latest.apk /pkg/efl-dev-latest.apk
134 - run: 123 - run:
135 name: Launch tests 124 name: Launch tests
136 command: | 125 command: |
@@ -149,27 +138,77 @@ jobs:
149 chmod +x .codecov 138 chmod +x .codecov
150 sed -i.bak 's/execdir/exec/' .codecov 139 sed -i.bak 's/execdir/exec/' .codecov
151 ./.codecov -Z 140 ./.codecov -Z
141 build_full_clang_efl_latest:
142 docker:
143 - image: borisfaure/terminology-ci:latest
144 environment:
145 - CC: clang
146 steps:
147 - restore_cache:
148 key: checkout-{{ .Environment.CIRCLE_SHA1 }}
149 - run:
150 name: Install EFL
151 command: apk add /pkg/efl-latest.apk /pkg/efl-dev-latest.apk
152 - run:
153 name: Compile with Clang
154 command: |
155 cd /terminology
156 meson -Dtests=true -Dfuzzing=true . build
157 meson configure build
158 cd build
159 ninja -j4
160 build_and_test_clang_ubsan_efl_latest:
161 docker:
162 - image: borisfaure/terminology-ci:latest
163 environment:
164 - CC: clang
165 - CFLAGS: -O0 -pipe -g -fno-omit-frame-pointer -fsanitize=undefined -fno-sanitize-recover=undefined
166 steps:
167 - restore_cache:
168 key: checkout-{{ .Environment.CIRCLE_SHA1 }}
169 - run:
170 name: Install EFL
171 command: apk add /pkg/efl-latest.apk /pkg/efl-dev-latest.apk
172 - run:
173 name: Compile with Clang
174 command: |
175 cd /terminology
176 meson -Dtests=true . build
177 meson configure build
178 cd build
179 ninja -j4
180 - run:
181 name: Launch tests
182 command: |
183 cd /terminology
184 tests/run_tests.sh -v -t build/src/bin/tytest -r tests/tests.results -d tests/
152path: /terminology 185path: /terminology
153workflows: 186workflows:
154 version: 2 187 version: 2
155 build-and-deploy: 188 build-and-deploy:
156 jobs: 189 jobs:
157 - checkout_code 190 - checkout_code
158 - build_full_gcc_efl-1.22: 191 - build_minimal_gcc_efl-1.20:
159 requires: 192 requires:
160 - checkout_code 193 - checkout_code
161 - build_minimal_gcc_efl-1.21: 194 - build_minimal_gcc_efl-1.21:
162 requires: 195 requires:
163 - checkout_code 196 - checkout_code
164 - build_minimal_gcc_efl-1.20: 197 - build_minimal_gcc_efl-1.22:
198 requires:
199 - checkout_code
200 - build_minimal_gcc_efl-1.23:
201 requires:
202 - checkout_code
203 - build_full_gcc_efl_latest:
165 requires: 204 requires:
166 - checkout_code 205 - checkout_code
167 - tests_gcc: 206 - tests_gcc_efl_latest:
168 requires: 207 requires:
169 - build_full_gcc_efl-1.22 208 - build_full_gcc_efl_latest
170 - build_full_clang_efl-1.22: 209 - build_full_clang_efl_latest:
171 requires: 210 requires:
172 - checkout_code 211 - checkout_code
173 - build_and_test_clang_ubsan_efl-1.22: 212 - build_and_test_clang_ubsan_efl_latest:
174 requires: 213 requires:
175 - checkout_code 214 - checkout_code
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
new file mode 100644
index 0000000..ce883be
--- /dev/null
+++ b/.github/FUNDING.yml
@@ -0,0 +1 @@
github: billiob
diff --git a/ChangeLog b/ChangeLog
index 6b5fc5e..c0e2a0d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,29 @@
12019-11-16
2 * Release v1.5.0
3 * Show title tab on splits, depending on configuration
4 * Show tabs that had a bell rang and had not been focused
5 * Add wizard on new configuration to set scaling
6 * Add scale configuration in the Settings panel
7 * Add Polish translation
8 * Themes: make tab title readable based on theme default colors
9 * Move the tab selector on the tab line
10 * Be able to select and copy tabs
11 * Better handle stalled unix socket when using one terminology with
12 multiple instances
13 * Change typop behavior to queue files in case there are multiple files to
14 look at
15 * Update Italian translation
16 * Fix live selections in the scrollback
17 * Fix unchecking "auto-hide cursor" not working
18 * Fix memory leaks related to looking for links under the mouse
19 * Ensure Terminology compiles with EFL-1.20
20 * Fix link detection over spaces
21 * Fix tab selector no longer taking into account the new destination
22 * Fix crash when using typop with multiple files
23 * No longer set environment variable DESKTOP_STARTUP_ID as it may no
24 longer be accurate
25 * Allow tabs to be pasted
26
12019-07-20 272019-07-20
2 * Release v1.5.0 28 * Release v1.5.0
3 * Handle emoji has double-width character, introduced in Unicode 9.0. 29 * Handle emoji has double-width character, introduced in Unicode 9.0.
diff --git a/ChangeLog.theme b/ChangeLog.theme
index a6acf98..2b2ba8d 100644
--- a/ChangeLog.theme
+++ b/ChangeLog.theme
@@ -9,6 +9,11 @@ Changes since 1.5.0:
9 * In group "terminology/background", add signals "tab,bell,on" and 9 * In group "terminology/background", add signals "tab,bell,on" and
10 "tab,bell,off" from "terminology" to set bell status on tab if there is a 10 "tab,bell,off" from "terminology" to set bell status on tab if there is a
11 tab. 11 tab.
12 * In group "terminology/background", change signals "tabcount,go",
13 "tabcount,prev", "tabcount,next" to "tab,go", "tab,prev" and "tab,next"
14 respectively.
15 * In group "terminology/background", add signal "tab,new" from "terminology"
16 to create a new tab.
12 17
13Changes since 1.2.0: 18Changes since 1.2.0:
14-------------------- 19--------------------
diff --git a/DESIGN.md b/DESIGN.md
index ba46615..e277a67 100644
--- a/DESIGN.md
+++ b/DESIGN.md
@@ -1,6 +1,7 @@
1A simple documentation to navige through the C files: 1A simple documentation to navige through the C files:
2 2
3* `src/bin/about.c` handles the About widget 3* `src/bin/about.c` handles the About widget
4* `src/bin/backlog.c`: backlog handling
4* `src/bin/col.c` is about the colors handled by the terminal 5* `src/bin/col.c` is about the colors handled by the terminal
5* `src/bin/config.c`: how the configuration is saved/loaded/updated 6* `src/bin/config.c`: how the configuration is saved/loaded/updated
6* `src/bin/controls.c`: the widget when a right-click is done on a terminal 7* `src/bin/controls.c`: the widget when a right-click is done on a terminal
@@ -33,7 +34,6 @@ A simple documentation to navige through the C files:
33* `src/bin/termptyext.c`: extented terminology escape handling 34* `src/bin/termptyext.c`: extented terminology escape handling
34* `src/bin/termptygfx.c`: charset translations 35* `src/bin/termptygfx.c`: charset translations
35* `src/bin/termptyops.c`: handling history 36* `src/bin/termptyops.c`: handling history
36* `src/bin/termptysave.c`: compression of the backlog
37* `src/bin/tyalpha.c`: the `tyalpha` tool 37* `src/bin/tyalpha.c`: the `tyalpha` tool
38* `src/bin/tybg.c`: the `tybg` tool 38* `src/bin/tybg.c`: the `tybg` tool
39* `src/bin/tycat.c`: the `tycat` tool 39* `src/bin/tycat.c`: the `tycat` tool
diff --git a/NEWS b/NEWS
index e992e23..59c9774 100644
--- a/NEWS
+++ b/NEWS
@@ -1,7 +1,40 @@
1================= 1=================
2Terminology 1.5.0 2Terminology 1.6.0
3================= 3=================
4 4
5Changes since 1.5.0:
6--------------------
7
8Additions:
9 * Show title tab on splits, depending on configuration
10 * Show tabs that had a bell rang and had not been focused
11 * Add wizard on new configuration to set scaling
12 * Add scale configuration in the Settings panel
13 * Add Polish translation
14
15Improvements:
16 * Themes: make tab title readable based on theme default colors
17 * Move the tab selector on the tab line
18 * Be able to select and copy tabs
19 * Better handle stalled unix socket when using one terminology with
20 multiple instances
21 * Change typop behavior to queue files in case there are multiple files to
22 look at
23 * Update Italian translation
24
25Fixes:
26 * Fix live selections in the scrollback
27 * Fix unchecking "auto-hide cursor" not working
28 * Fix memory leaks related to looking for links under the mouse
29 * Ensure Terminology compiles with EFL-1.20
30 * Fix link detection over spaces
31 * Fix tab selector no longer taking into account the new destination
32 * Fix crash when using typop with multiple files
33 * No longer set environment variable DESKTOP_STARTUP_ID as it may no
34 longer be accurate
35 * Allow tabs to be pasted
36
37
5Changes since 1.4.1: 38Changes since 1.4.1:
6-------------------- 39--------------------
7 40
diff --git a/README.md b/README.md
index 796c230..3ef7464 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
1Terminology 1.5.0 1Terminology 1.6.0
2================= 2=================
3 3
4This is an EFL terminal emulator with some extra bells and whistles. 4This is an EFL terminal emulator with some extra bells and whistles.
@@ -14,7 +14,8 @@ This is an EFL terminal emulator with some extra bells and whistles.
14[![CircleCI](https://circleci.com/gh/billiob/terminology.svg?style=shield)](https://circleci.com/gh/billiob/terminology) 14[![CircleCI](https://circleci.com/gh/billiob/terminology.svg?style=shield)](https://circleci.com/gh/billiob/terminology)
15[![codecov](https://codecov.io/gh/billiob/terminology/branch/master/graph/badge.svg)](https://codecov.io/gh/billiob/terminology) 15[![codecov](https://codecov.io/gh/billiob/terminology/branch/master/graph/badge.svg)](https://codecov.io/gh/billiob/terminology)
16[![Codacy Badge](https://api.codacy.com/project/badge/Grade/49a51811016a44279cb969af82cd246f)](https://www.codacy.com/app/billiob/terminology) 16[![Codacy Badge](https://api.codacy.com/project/badge/Grade/49a51811016a44279cb969af82cd246f)](https://www.codacy.com/app/billiob/terminology)
17 17[![Twitter: _Terminology_](https://img.shields.io/twitter/follow/_Terminology_?style=social)](https://twitter.com/_Terminology_)
18[![terminology](https://snapcraft.io//terminology/badge.svg)](https://snapcraft.io/terminology)
18 19
19Requirements 20Requirements
20------------ 21------------
diff --git a/data/desktop/meson.build b/data/desktop/meson.build
index 1eb4019..8c16dbe 100644
--- a/data/desktop/meson.build
+++ b/data/desktop/meson.build
@@ -1,2 +1,12 @@
1install_data('terminology.desktop', 1icon_sed = 's~%ICON_PATH%~@0@~'.format(join_paths(get_option('prefix'),
2 install_dir: join_paths(get_option('datadir'), 'applications')) 2 get_option('datadir'),
3 'icons/hicolor/128x128/apps'))
4
5custom_target(
6 'terminology.desktop',
7 input : 'terminology.desktop.in',
8 output: 'terminology.desktop',
9 command : [sed, icon_sed, '@INPUT@'],
10 capture : true,
11 install : true,
12 install_dir : join_paths(get_option('datadir'), 'applications'))
diff --git a/data/desktop/terminology.desktop b/data/desktop/terminology.desktop.in
index 020891d..5fcfa40 100644
--- a/data/desktop/terminology.desktop
+++ b/data/desktop/terminology.desktop.in
@@ -12,6 +12,7 @@ Comment=Terminal emulator
12Comment[da]=Terminalemulator 12Comment[da]=Terminalemulator
13Comment[eo]=Terminalimitilo 13Comment[eo]=Terminalimitilo
14Comment[es]=Emulador de terminal 14Comment[es]=Emulador de terminal
15Comment[fr]=Émulateur de terminal
15Comment[gl]=Emulador de terminal 16Comment[gl]=Emulador de terminal
16Comment[it]=Emulatore di terminale 17Comment[it]=Emulatore di terminale
17Comment[pt]=Emulador de terminal 18Comment[pt]=Emulador de terminal
@@ -19,6 +20,6 @@ Comment[ru]=Эмулятор терминала
19Comment[ko]=터미널 에뮬레이터 20Comment[ko]=터미널 에뮬레이터
20Keywords=shell;prompt;command;commandline; 21Keywords=shell;prompt;command;commandline;
21Exec=terminology 22Exec=terminology
22Icon=terminology 23Icon=%ICON_PATH%/terminology.png
23Categories=System;TerminalEmulator; 24Categories=System;TerminalEmulator;
24StartupWMClass=terminology 25StartupWMClass=terminology
diff --git a/data/themes/default.edc b/data/themes/default.edc
index c98e91d..af1f8e9 100644
--- a/data/themes/default.edc
+++ b/data/themes/default.edc
@@ -629,15 +629,19 @@ collections {
629 } 629 }
630 program { 630 program {
631 signal: "mouse,clicked,1"; source: "tabcount_ev"; 631 signal: "mouse,clicked,1"; source: "tabcount_ev";
632 action: SIGNAL_EMIT "tabcount,go" "terminology"; 632 action: SIGNAL_EMIT "tab,go" "terminology";
633 }
634 program {
635 signal: "mouse,clicked,3"; source: "tabcount_ev";
636 action: SIGNAL_EMIT "tab,new" "terminology";
633 } 637 }
634 program { 638 program {
635 signal: "mouse,wheel,0,1"; source: "tabcount_ev"; 639 signal: "mouse,wheel,0,1"; source: "tabcount_ev";
636 action: SIGNAL_EMIT "tabcount,prev" "terminology"; 640 action: SIGNAL_EMIT "tab,prev" "terminology";
637 } 641 }
638 program { 642 program {
639 signal: "mouse,wheel,0,-1"; source: "tabcount_ev"; 643 signal: "mouse,wheel,0,-1"; source: "tabcount_ev";
640 action: SIGNAL_EMIT "tabcount,next" "terminology"; 644 action: SIGNAL_EMIT "tab,next" "terminology";
641 } 645 }
642 program { 646 program {
643 signal: "tabcount,off"; source: "terminology"; 647 signal: "tabcount,off"; source: "terminology";
@@ -1332,6 +1336,253 @@ collections {
1332 target: "tabtitle"; 1336 target: "tabtitle";
1333 target: "tabclose"; 1337 target: "tabclose";
1334 } 1338 }
1339 program {
1340 signal: "tab_btn,on"; source: "terminology";
1341 action: STATE_SET "on" 0.0;
1342 target: "tab_btn_clip";
1343 target: "tab_btn_bg";
1344 target: "terminology.tab_btn";
1345 }
1346 program {
1347 signal: "tab_btn,off"; source: "terminology";
1348 action: STATE_SET "default" 0.0;
1349 target: "tab_btn_clip";
1350 target: "tab_btn_bg";
1351 target: "terminology.tab_btn";
1352 }
1353 part { name: "tab_btn_clip"; type: RECT;
1354 description { state: "default" 0.0;
1355 color: 255 255 255 0;
1356 visible: 0;
1357 }
1358 description { state: "on" 0.0;
1359 inherit: "default" 0.0;
1360 visible: 1;
1361 color: 255 255 255 255;
1362 }
1363 }
1364 part { name: "tab_btn_bg";
1365 mouse_events: 0;
1366 clip_to: "tab_btn_clip";
1367 description { state: "default" 0.0;
1368 fixed: 1 1;
1369 rel1.to: "terminology.tab_btn";
1370 rel2.to: "terminology.tab_btn";
1371 image.normal: "tab_bg_r0.png";
1372 image.border: 0 2 4 4;
1373 fill.smooth: 0;
1374 visible: 0;
1375 fixed: 1 1;
1376 }
1377 description { state: "on" 0.0;
1378 inherit: "default" 0.0;
1379 visible: 1;
1380 }
1381 }
1382 part { name: "tab_btn_glow_r0";
1383 clip_to: "tab_btn_clip";
1384 description { state: "default" 0.0;
1385 fixed: 1 1;
1386 rel1.to: "tab_btn_r0";
1387 rel2.to: "tab_btn_r0";
1388 rel1.offset: -4 -4;
1389 rel2.offset: 3 3;
1390 image {
1391 normal: "cr_glow.png";
1392 border: 9 9 9 9;
1393 }
1394 color: 51 153 255 32;
1395 }
1396 description { state: "over" 0.0;
1397 inherit: "default" 0.0;
1398 color: 51 153 255 255;
1399 }
1400 }
1401 part { name: "tab_btn_glow_r1";
1402 clip_to: "tab_btn_clip";
1403 description { state: "default" 0.0;
1404 fixed: 1 1;
1405 rel1.to: "tab_btn_r1";
1406 rel2.to: "tab_btn_r1";
1407 rel1.offset: -4 -4;
1408 rel2.offset: 3 3;
1409 image {
1410 normal: "cr_glow.png";
1411 border: 9 9 9 9;
1412 }
1413 color: 51 153 255 32;
1414 }
1415 description { state: "over" 0.0;
1416 inherit: "default" 0.0;
1417 color: 51 153 255 255;
1418 }
1419 }
1420 part { name: "tab_btn_glow_r2";
1421 clip_to: "tab_btn_clip";
1422 description { state: "default" 0.0;
1423 fixed: 1 1;
1424 rel1.to: "tab_btn_r2";
1425 rel2.to: "tab_btn_r2";
1426 rel1.offset: -4 -4;
1427 rel2.offset: 3 3;
1428 image {
1429 normal: "cr_glow.png";
1430 border: 9 9 9 9;
1431 }
1432 color: 51 153 255 32;
1433 }
1434 description { state: "over" 0.0;
1435 inherit: "default" 0.0;
1436 color: 51 153 255 255;
1437 }
1438 }
1439 part { name: "tab_btn_glow_r3";
1440 clip_to: "tab_btn_clip";
1441 description { state: "default" 0.0;
1442 fixed: 1 1;
1443 rel1.to: "tab_btn_r3";
1444 rel2.to: "tab_btn_r3";
1445 rel1.offset: -4 -4;
1446 rel2.offset: 3 3;
1447 image {
1448 normal: "cr_glow.png";
1449 border: 9 9 9 9;
1450 }
1451 color: 51 153 255 32;
1452 }
1453 description { state: "over" 0.0;
1454 inherit: "default" 0.0;
1455 color: 51 153 255 255;
1456 }
1457 }
1458 part { name: "tab_btn_r0"; type: RECT;
1459 clip_to: "tab_btn_clip";
1460 description { state: "default" 0.0;
1461 fixed: 1 1;
1462 rel1.to: "terminology.tab_btn";
1463 rel2.to: "terminology.tab_btn";
1464 rel1.relative: 0.05 0.05;
1465 rel2.relative: 0.45 0.45;
1466 color: 255 255 255 32;
1467 }
1468 description { state: "over" 0.0;
1469 inherit: "default" 0.0;
1470 color: 255 255 255 255;
1471 }
1472 }
1473 part { name: "tab_btn_r1"; type: RECT;
1474 clip_to: "tab_btn_clip";
1475 description { state: "default" 0.0;
1476 fixed: 1 1;
1477 rel1.to: "terminology.tab_btn";
1478 rel2.to: "terminology.tab_btn";
1479 rel1.relative: 0.55 0.05;
1480 rel2.relative: 0.95 0.45;
1481 color: 255 255 255 32;
1482 }
1483 description { state: "over" 0.0;
1484 inherit: "default" 0.0;
1485 color: 255 255 255 255;
1486 }
1487 }
1488 part { name: "tab_btn_r2"; type: RECT;
1489 clip_to: "tab_btn_clip";
1490 description { state: "default" 0.0;
1491 fixed: 1 1;
1492 rel1.to: "terminology.tab_btn";
1493 rel2.to: "terminology.tab_btn";
1494 rel1.relative: 0.05 0.55;
1495 rel2.relative: 0.45 0.95;
1496 color: 255 255 255 32;
1497 }
1498 description { state: "over" 0.0;
1499 inherit: "default" 0.0;
1500 color: 255 255 255 255;
1501 }
1502 }
1503 part { name: "tab_btn_r3"; type: RECT;
1504 clip_to: "tab_btn_clip";
1505 description { state: "default" 0.0;
1506 fixed: 1 1;
1507 rel1.to: "terminology.tab_btn";
1508 rel2.to: "terminology.tab_btn";
1509 rel1.relative: 0.55 0.55;
1510 rel2.relative: 0.95 0.95;
1511 color: 255 255 255 32;
1512 }
1513 description { state: "over" 0.0;
1514 inherit: "default" 0.0;
1515 color: 255 255 255 255;
1516 }
1517 }
1518 part { name: "terminology.tab_btn"; type: SWALLOW;
1519 clip_to: "tab_btn_clip";
1520 mouse_events: 0;
1521 description { state: "default" 0.0;
1522 rel1.relative: 1.0 0.0;
1523 rel2.to_y: "tabmiddle";
1524 color: 250 0 250 255;
1525 visible: 0;
1526 align: 1.0 0.0;
1527 fixed: 1 1;
1528 }
1529 description { state: "on" 0.0;
1530 inherit: "default" 0.0;
1531 min: 16 16;
1532 visible: 1;
1533 }
1534 }
1535 part { name: "tab_btn_ev"; type: RECT; repeat_events: 1;
1536 clip_to: "tab_btn_clip";
1537 description { state: "default" 0.0;
1538 fixed: 1 1;
1539 rel1.to: "terminology.tab_btn";
1540 rel2.to: "terminology.tab_btn";
1541 color: 0 0 0 0;
1542 }
1543 }
1544 program {
1545 signal: "mouse,in"; source: "tab_btn_ev";
1546 action: STATE_SET "over" 0.0;
1547 transition: DECELERATE 0.5;
1548 target: "tab_btn_r0";
1549 target: "tab_btn_r1";
1550 target: "tab_btn_r2";
1551 target: "tab_btn_r3";
1552 target: "tab_btn_glow_r0";
1553 target: "tab_btn_glow_r1";
1554 target: "tab_btn_glow_r2";
1555 target: "tab_btn_glow_r3";
1556 }
1557 program {
1558 signal: "mouse,out"; source: "tab_btn_ev";
1559 action: STATE_SET "default" 0.0;
1560 transition: DECELERATE 2.0;
1561 target: "tab_btn_r0";
1562 target: "tab_btn_r1";
1563 target: "tab_btn_r2";
1564 target: "tab_btn_r3";
1565 target: "tab_btn_glow_r0";
1566 target: "tab_btn_glow_r1";
1567 target: "tab_btn_glow_r2";
1568 target: "tab_btn_glow_r3";
1569 }
1570 program {
1571 signal: "mouse,clicked,1"; source: "tab_btn_ev";
1572 action: SIGNAL_EMIT "tab,go" "terminology";
1573 }
1574 program {
1575 signal: "mouse,clicked,3"; source: "tab_btn_ev";
1576 action: SIGNAL_EMIT "tab,new" "terminology";
1577 }
1578 program {
1579 signal: "mouse,wheel,0,1"; source: "tab_btn_ev";
1580 action: SIGNAL_EMIT "tab,prev" "terminology";
1581 }
1582 program {
1583 signal: "mouse,wheel,0,-1"; source: "tab_btn_ev";
1584 action: SIGNAL_EMIT "tab,next" "terminology";
1585 }
1335 1586
1336 part { name: "terminology.tab"; type: SWALLOW; 1587 part { name: "terminology.tab"; type: SWALLOW;
1337 mouse_events: 0; 1588 mouse_events: 0;
@@ -1348,11 +1599,12 @@ collections {
1348 // some slot for dragable parts to stay in along top edge of bg 1599 // some slot for dragable parts to stay in along top edge of bg
1349 part { name: "tabdrag"; type: SPACER; 1600 part { name: "tabdrag"; type: SPACER;
1350 description { state: "default" 0.0; 1601 description { state: "default" 0.0;
1351 rel2.relative: 1.0 0.0; 1602 rel2.relative: 0.0 0.0;
1603 rel2.to_x: "terminology.tab_btn";
1352 fixed: 1 1; 1604 fixed: 1 1;
1353 } 1605 }
1354 } 1606 }
1355 // left boundary of the active tab (ragable 0.0 -> 1.0) 1607 // left boundary of the active tab (dragable 0.0 -> 1.0)
1356 part { name: "terminology.tabl"; type: SPACER; 1608 part { name: "terminology.tabl"; type: SPACER;
1357 dragable.x: 1 1 0; 1609 dragable.x: 1 1 0;
1358 dragable.confine: "tabdrag"; 1610 dragable.confine: "tabdrag";
@@ -1362,12 +1614,13 @@ collections {
1362 fixed: 1 1; 1614 fixed: 1 1;
1363 } 1615 }
1364 } 1616 }
1365 // right boundary of the active tab (ragable 0.0 -> 1.0) 1617 // right boundary of the active tab (dragable 0.0 -> 1.0)
1366 part { name: "terminology.tabr"; type: SPACER; 1618 part { name: "terminology.tabr"; type: SPACER;
1367 dragable.x: 1 1 0; 1619 dragable.x: 1 1 0;
1368 dragable.confine: "tabdrag"; 1620 dragable.confine: "tabdrag";
1369 description { state: "default" 0.0; 1621 description { state: "default" 0.0;
1370 rel2.relative: 1.0 0.0; 1622 rel2.relative: 0.0 0.0;
1623 rel2.to_x: "terminology.tab_btn";
1371 max: 1 1; 1624 max: 1 1;
1372 fixed: 1 1; 1625 fixed: 1 1;
1373 } 1626 }
@@ -1466,7 +1719,9 @@ collections {
1466 description { state: "default" 0.0; 1719 description { state: "default" 0.0;
1467 rel1.to: "terminology.tab"; 1720 rel1.to: "terminology.tab";
1468 rel1.relative: 1.0 0.0; 1721 rel1.relative: 1.0 0.0;
1722 rel2.to_x: "terminology.tab_btn";
1469 rel2.to_y: "tabmiddle"; 1723 rel2.to_y: "tabmiddle";
1724 rel2.relative: 0.0 1.0;
1470 color: 0 0 0 0; 1725 color: 0 0 0 0;
1471 visible: 0; 1726 visible: 0;
1472 fixed: 1 1; 1727 fixed: 1 1;
diff --git a/data/themes/mild.edc b/data/themes/mild.edc
index f8a79d0..bd5f63c 100644
--- a/data/themes/mild.edc
+++ b/data/themes/mild.edc
@@ -442,7 +442,19 @@ collections {
442 } 442 }
443 program { 443 program {
444 signal: "mouse,clicked,1"; source: "tabcount_ev"; 444 signal: "mouse,clicked,1"; source: "tabcount_ev";
445 action: SIGNAL_EMIT "tabcount,go" "terminology"; 445 action: SIGNAL_EMIT "tab,go" "terminology";
446 }
447 program {
448 signal: "mouse,clicked,3"; source: "tabcount_ev";
449 action: SIGNAL_EMIT "tab,new" "terminology";
450 }
451 program {
452 signal: "mouse,wheel,0,1"; source: "tabcount_ev";
453 action: SIGNAL_EMIT "tab,prev" "terminology";
454 }
455 program {
456 signal: "mouse,wheel,0,-1"; source: "tabcount_ev";
457 action: SIGNAL_EMIT "tab,next" "terminology";
446 } 458 }
447 program { 459 program {
448 signal: "tabcount,off"; source: "terminology"; 460 signal: "tabcount,off"; source: "terminology";
@@ -635,6 +647,254 @@ collections {
635 target: "tabtitle"; 647 target: "tabtitle";
636 } 648 }
637 649
650 program {
651 signal: "tab_btn,on"; source: "terminology";
652 action: STATE_SET "on" 0.0;
653 target: "tab_btn_clip";
654 target: "tab_btn_bg";
655 target: "terminology.tab_btn";
656 }
657 program {
658 signal: "tab_btn,off"; source: "terminology";
659 action: STATE_SET "default" 0.0;
660 target: "tab_btn_clip";
661 target: "tab_btn_bg";
662 target: "terminology.tab_btn";
663 }
664 part { name: "tab_btn_clip"; type: RECT;
665 description { state: "default" 0.0;
666 color: 255 255 255 0;
667 visible: 0;
668 }
669 description { state: "on" 0.0;
670 inherit: "default" 0.0;
671 visible: 1;
672 color: 255 255 255 255;
673 }
674 }
675 part { name: "tab_btn_bg";
676 mouse_events: 0;
677 clip_to: "tab_btn_clip";
678 description { state: "default" 0.0;
679 fixed: 1 1;
680 rel1.to: "terminology.tab_btn";
681 rel2.to: "terminology.tab_btn";
682 image.normal: "tab_bg_r0.png";
683 image.border: 0 2 4 4;
684 fill.smooth: 0;
685 visible: 0;
686 fixed: 1 1;
687 }
688 description { state: "on" 0.0;
689 inherit: "default" 0.0;
690 visible: 1;
691 }
692 }
693 part { name: "tab_btn_glow_r0";
694 clip_to: "tab_btn_clip";
695 description { state: "default" 0.0;
696 fixed: 1 1;
697 rel1.to: "tab_btn_r0";
698 rel2.to: "tab_btn_r0";
699 rel1.offset: -4 -4;
700 rel2.offset: 3 3;
701 image {
702 normal: "cr_glow.png";
703 border: 9 9 9 9;
704 }
705 color: 51 153 255 32;
706 }
707 description { state: "over" 0.0;
708 inherit: "default" 0.0;
709 color: 51 153 255 255;
710 }
711 }
712 part { name: "tab_btn_glow_r1";
713 clip_to: "tab_btn_clip";
714 description { state: "default" 0.0;
715 fixed: 1 1;
716 rel1.to: "tab_btn_r1";
717 rel2.to: "tab_btn_r1";
718 rel1.offset: -4 -4;
719 rel2.offset: 3 3;
720 image {
721 normal: "cr_glow.png";
722 border: 9 9 9 9;
723 }
724 color: 51 153 255 32;
725 }
726 description { state: "over" 0.0;
727 inherit: "default" 0.0;
728 color: 51 153 255 255;
729 }
730 }
731 part { name: "tab_btn_glow_r2";
732 clip_to: "tab_btn_clip";
733 description { state: "default" 0.0;
734 fixed: 1 1;
735 rel1.to: "tab_btn_r2";
736 rel2.to: "tab_btn_r2";
737 rel1.offset: -4 -4;
738 rel2.offset: 3 3;
739 image {
740 normal: "cr_glow.png";
741 border: 9 9 9 9;
742 }
743 color: 51 153 255 32;
744 }
745 description { state: "over" 0.0;
746 inherit: "default" 0.0;
747 color: 51 153 255 255;
748 }
749 }
750 part { name: "tab_btn_glow_r3";
751 clip_to: "tab_btn_clip";
752 description { state: "default" 0.0;
753 fixed: 1 1;
754 rel1.to: "tab_btn_r3";
755 rel2.to: "tab_btn_r3";
756 rel1.offset: -4 -4;
757 rel2.offset: 3 3;
758 image {
759 normal: "cr_glow.png";
760 border: 9 9 9 9;
761 }
762 color: 51 153 255 32;
763 }
764 description { state: "over" 0.0;
765 inherit: "default" 0.0;
766 color: 51 153 255 255;
767 }
768 }
769 part { name: "tab_btn_r0"; type: RECT;
770 clip_to: "tab_btn_clip";
771 description { state: "default" 0.0;
772 fixed: 1 1;
773 rel1.to: "terminology.tab_btn";
774 rel2.to: "terminology.tab_btn";
775 rel1.relative: 0.05 0.05;
776 rel2.relative: 0.45 0.45;
777 color: 255 255 255 32;
778 }
779 description { state: "over" 0.0;
780 inherit: "default" 0.0;
781 color: 255 255 255 255;
782 }
783 }
784 part { name: "tab_btn_r1"; type: RECT;
785 clip_to: "tab_btn_clip";
786 description { state: "default" 0.0;
787 fixed: 1 1;
788 rel1.to: "terminology.tab_btn";
789 rel2.to: "terminology.tab_btn";
790 rel1.relative: 0.55 0.05;
791 rel2.relative: 0.95 0.45;
792 color: 255 255 255 32;
793 }
794 description { state: "over" 0.0;
795 inherit: "default" 0.0;
796 color: 255 255 255 255;
797 }
798 }
799 part { name: "tab_btn_r2"; type: RECT;
800 clip_to: "tab_btn_clip";
801 description { state: "default" 0.0;
802 fixed: 1 1;
803 rel1.to: "terminology.tab_btn";
804 rel2.to: "terminology.tab_btn";
805 rel1.relative: 0.05 0.55;
806 rel2.relative: 0.45 0.95;
807 color: 255 255 255 32;
808 }
809 description { state: "over" 0.0;
810 inherit: "default" 0.0;
811 color: 255 255 255 255;
812 }
813 }
814 part { name: "tab_btn_r3"; type: RECT;
815 clip_to: "tab_btn_clip";
816 description { state: "default" 0.0;
817 fixed: 1 1;
818 rel1.to: "terminology.tab_btn";
819 rel2.to: "terminology.tab_btn";
820 rel1.relative: 0.55 0.55;
821 rel2.relative: 0.95 0.95;
822 color: 255 255 255 32;
823 }
824 description { state: "over" 0.0;
825 inherit: "default" 0.0;
826 color: 255 255 255 255;
827 }
828 }
829 part { name: "terminology.tab_btn"; type: SWALLOW;
830 clip_to: "tab_btn_clip";
831 mouse_events: 0;
832 description { state: "default" 0.0;
833 rel1.relative: 1.0 0.0;
834 rel2.to_y: "tabmiddle";
835 color: 250 0 250 255;
836 visible: 0;
837 align: 1.0 0.0;
838 fixed: 1 1;
839 }
840 description { state: "on" 0.0;
841 inherit: "default" 0.0;
842 min: 16 16;
843 visible: 1;
844 }
845 }
846 part { name: "tab_btn_ev"; type: RECT; repeat_events: 1;
847 clip_to: "tab_btn_clip";
848 description { state: "default" 0.0;
849 fixed: 1 1;
850 rel1.to: "terminology.tab_btn";
851 rel2.to: "terminology.tab_btn";
852 color: 0 0 0 0;
853 }
854 }
855 program {
856 signal: "mouse,in"; source: "tab_btn_ev";
857 action: STATE_SET "over" 0.0;
858 transition: DECELERATE 0.5;
859 target: "tab_btn_r0";
860 target: "tab_btn_r1";
861 target: "tab_btn_r2";
862 target: "tab_btn_r3";
863 target: "tab_btn_glow_r0";
864 target: "tab_btn_glow_r1";
865 target: "tab_btn_glow_r2";
866 target: "tab_btn_glow_r3";
867 }
868 program {
869 signal: "mouse,out"; source: "tab_btn_ev";
870 action: STATE_SET "default" 0.0;
871 transition: DECELERATE 2.0;
872 target: "tab_btn_r0";
873 target: "tab_btn_r1";
874 target: "tab_btn_r2";
875 target: "tab_btn_r3";
876 target: "tab_btn_glow_r0";
877 target: "tab_btn_glow_r1";
878 target: "tab_btn_glow_r2";
879 target: "tab_btn_glow_r3";
880 }
881 program {
882 signal: "mouse,clicked,1"; source: "tab_btn_ev";
883 action: SIGNAL_EMIT "tab,go" "terminology";
884 }
885 program {
886 signal: "mouse,clicked,3"; source: "tab_btn_ev";
887 action: SIGNAL_EMIT "tab,new" "terminology";
888 }
889 program {
890 signal: "mouse,wheel,0,1"; source: "tab_btn_ev";
891 action: SIGNAL_EMIT "tab,prev" "terminology";
892 }
893 program {
894 signal: "mouse,wheel,0,-1"; source: "tab_btn_ev";
895 action: SIGNAL_EMIT "tab,next" "terminology";
896 }
897
638 part { name: "terminology.tab"; type: SWALLOW; 898 part { name: "terminology.tab"; type: SWALLOW;
639 mouse_events: 0; 899 mouse_events: 0;
640 description { state: "default" 0.0; 900 description { state: "default" 0.0;
@@ -650,11 +910,12 @@ collections {
650 // some slot for dragable parts to stayt in along top edge of bg 910 // some slot for dragable parts to stayt in along top edge of bg
651 part { name: "tabdrag"; type: SPACER; 911 part { name: "tabdrag"; type: SPACER;
652 description { state: "default" 0.0; 912 description { state: "default" 0.0;
653 rel2.relative: 1.0 0.0; 913 rel2.relative: 0.0 0.0;
914 rel2.to_x: "terminology.tab_btn";
654 fixed: 1 1; 915 fixed: 1 1;
655 } 916 }
656 } 917 }
657 // left boundary of the active tab (ragable 0.0 -> 1.0) 918 // left boundary of the active tab (dragable 0.0 -> 1.0)
658 part { name: "terminology.tabl"; type: SPACER; 919 part { name: "terminology.tabl"; type: SPACER;
659 dragable.x: 1 1 0; 920 dragable.x: 1 1 0;
660 dragable.confine: "tabdrag"; 921 dragable.confine: "tabdrag";
@@ -664,12 +925,13 @@ collections {
664 fixed: 1 1; 925 fixed: 1 1;
665 } 926 }
666 } 927 }
667 // right boundary of the active tab (ragable 0.0 -> 1.0) 928 // right boundary of the active tab (dragable 0.0 -> 1.0)
668 part { name: "terminology.tabr"; type: SPACER; 929 part { name: "terminology.tabr"; type: SPACER;
669 dragable.x: 1 1 0; 930 dragable.x: 1 1 0;
670 dragable.confine: "tabdrag"; 931 dragable.confine: "tabdrag";
671 description { state: "default" 0.0; 932 description { state: "default" 0.0;
672 rel2.relative: 1.0 0.0; 933 rel2.relative: 0.0 0.0;
934 rel2.to_x: "terminology.tab_btn";
673 max: 1 1; 935 max: 1 1;
674 fixed: 1 1; 936 fixed: 1 1;
675 } 937 }
diff --git a/man/terminology-helpers.1 b/man/terminology-helpers.1
index 901ed3e..cbb1eba 100644
--- a/man/terminology-helpers.1
+++ b/man/terminology-helpers.1
@@ -1,5 +1,5 @@
1.\" Manpage for terminology helpers 1.\" Manpage for terminology helpers
2.TH TERMINOLOGY-HELPERS 1 "Jul 20, 2019" 2.TH TERMINOLOGY-HELPERS 1 "Nov 16, 2019"
3.SH NAME 3.SH NAME
4terminiology-helpers \- programs that enhance 4terminiology-helpers \- programs that enhance
5.B terminology(1) 5.B terminology(1)
diff --git a/man/terminology.1 b/man/terminology.1
index 1ee3b60..3d840f9 100644
--- a/man/terminology.1
+++ b/man/terminology.1
@@ -1,5 +1,5 @@
1.\" Manpage for Terminology 1.\" Manpage for Terminology
2.TH TERMINOLOGY 1 "Jul 20, 2019" "1.5.0" "Terminology man page" 2.TH TERMINOLOGY 1 "Nov 16, 2019" "1.6.0" "Terminology man page"
3.SH NAME 3.SH NAME
4Terminology \- Terminal Emulator written with EFL (Enlightenment Foundation Libraries). 4Terminology \- Terminal Emulator written with EFL (Enlightenment Foundation Libraries).
5.SH SYNOPSIS 5.SH SYNOPSIS
diff --git a/meson.build b/meson.build
index 2f52f5a..36ac0e0 100644
--- a/meson.build
+++ b/meson.build
@@ -1,5 +1,5 @@
1project('terminology', 'c', 1project('terminology', 'c',
2 version: '1.5.99', 2 version: '1.6.99',
3 default_options: ['buildtype=plain', 'c_std=gnu99'], 3 default_options: ['buildtype=plain', 'c_std=gnu99'],
4 license: 'BSD') 4 license: 'BSD')
5 5
@@ -78,6 +78,10 @@ if cc.has_function('mkstemps')
78 config_data.set('HAVE_MKSTEMPS', 1) 78 config_data.set('HAVE_MKSTEMPS', 1)
79endif 79endif
80 80
81if cc.has_function('strchrnul')
82 config_data.set('HAVE_STRCHRNUL', 1)
83endif
84
81url_head_code = '''#include <Ecore_Con.h> 85url_head_code = '''#include <Ecore_Con.h>
82int main(void) { ecore_con_url_head(NULL); return 0; } 86int main(void) { ecore_con_url_head(NULL); return 0; }
83''' 87'''
@@ -123,6 +127,8 @@ endif
123 127
124message('edje_cc set to:' + edje_cc) 128message('edje_cc set to:' + edje_cc)
125 129
130sed = find_program('sed')
131
126configure_file(output: 'terminology_config.h', 132configure_file(output: 'terminology_config.h',
127 configuration: config_data) 133 configuration: config_data)
128 134
diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml
new file mode 100644
index 0000000..737a586
--- /dev/null
+++ b/snap/snapcraft.yaml
@@ -0,0 +1,174 @@
1name: terminology
2version: git
3summary: Terminal Emulator written with the Enlightenment Foundation Libraries
4description: |
5 Terminology is a terminal emulator for Linux/BSD/UNIX systems that uses EFL.
6 It has a whole bunch of bells and whistles. Use it as your regular vt100
7 terminal emulator with all the usual features, such as 256 color support.
8 Terminology is designed to emulate Xterm as closely as possible in most
9 respects.
10base: core18
11license: BSD-2-Clause
12confinement: classic
13grade: stable
14icon: data/images/terminology.png
15apps:
16 terminology:
17 command: terminology
18 desktop: usr/share/applications/terminology.desktop
19 tyalpha:
20 command: tyalpha
21 tybg:
22 command: tybg
23 tycat:
24 command: tycat
25 tyls:
26 command: tyls
27 typop:
28 command: typop
29 tyq:
30 command: tyq
31 tysend:
32 command: tysend
33parts:
34 efl:
35 plugin: meson
36 source-type: tar
37 source: https://download.enlightenment.org/rel/libs/efl/efl-1.23.2.tar.xz
38 meson-parameters:
39 - --prefix=/usr
40 - --libdir=/usr/lib
41 - --buildtype=release
42 - --default-library=shared
43 - -Dnls=false
44 - -Dopengl=es-egl
45 - -Dxinput22=true
46 - -Dbuffer=false
47 - -Dfb=false
48 - -Ddrm=false
49 - -Dtslib=false
50 - -Dharfbuzz=true
51 - -Dwl=true
52 - -Dnetwork-backend=connman
53 - -Devas-loaders-disabler=pdf,ps,raw,tiff,json,webp
54 - -Dphysics=false
55 - -Davahi=false
56 - -Deeze=false
57 - -Dbindings=
58 - -Dbuild-examples=false
59 - -Dbuild-tests=false
60 build-packages:
61 - gcc
62 - pkg-config
63 - libdbus-1-dev
64 - libssl-dev
65 - libfontconfig1-dev
66 - libfreetype6-dev
67 - libfribidi-dev
68 - libgif-dev
69 - libgstreamer1.0-dev
70 - libgstreamer-plugins-base1.0-dev
71 - libharfbuzz-dev
72 - libjpeg-turbo8-dev
73 - libpng-dev
74 - libpulse-dev
75 - librsvg2-dev
76 - libsndfile1-dev
77 - libx11-dev
78 - libxkbcommon-dev
79 - libxkbcommon-x11-dev
80 - libxcomposite-dev
81 - libxcursor-dev
82 - libxdamage-dev
83 - libxinerama-dev
84 - libxrandr-dev
85 - libxss-dev
86 - libxtst-dev
87 - libsystemd-dev
88 - libluajit-5.1-dev
89 - libibus-1.0-dev
90 - libscim-dev
91 stage-packages:
92 - libcairo2
93 - libcroco3
94 - libdatrie1
95 - libegl1
96 - libfontconfig1
97 - libfreetype6
98 - libfribidi0
99 - libgdk-pixbuf2.0-0
100 - libgif7
101 - libgles2
102 - libglvnd0
103 - libgraphite2-3
104 - libgstreamer-plugins-base1.0-0
105 - libgstreamer1.0-0
106 - libharfbuzz0b
107 - libibus-1.0-5
108 - libicu60
109 - libjpeg-turbo8
110 - libluajit-5.1-2
111 - liborc-0.4-0
112 - libpango-1.0-0
113 - libpangocairo-1.0-0
114 - libpangoft2-1.0-0
115 - libpixman-1-0
116 - libpng16-16
117 - librsvg2-2
118 - libthai0
119 - libwayland-egl1
120 - libx11-6
121 - libx11-xcb1
122 - libxau6
123 - libxcb-render0
124 - libxcb-shm0
125 - libxcb1
126 - libxcomposite1
127 - libxcursor1
128 - libxdamage1
129 - libxdmcp6
130 - libxext6
131 - libxfixes3
132 - libxi6
133 - libxinerama1
134 - libxkbcommon-x11-0
135 - libxml2
136 - libxrandr2
137 - libxrender1
138 - libxss1
139 - libxtst6
140 terminology:
141 plugin: meson
142 after: [ efl ]
143 source-type: git
144 source: https://github.com/billiob/terminology
145 meson-parameters:
146 - --prefix=/usr
147 stage-packages:
148 - libcurl4
149 - libfontconfig1
150 - libfreetype6
151 - libfribidi0
152 - libgif7
153 - libgraphite2-3
154 - libharfbuzz0b
155 - libjpeg-turbo8
156 - libluajit-5.1-2
157 - libpcre3
158 - libpng16-16
159 - libx11-6
160 - libx11-xcb1
161 - libxau6
162 - libxcb1
163 - libxcomposite1
164 - libxcursor1
165 - libxdamage1
166 - libxdmcp6
167 - libxext6
168 - libxfixes3
169 - libxi6
170 - libxinerama1
171 - libxrandr2
172 - libxrender1
173 - libxss1
174 - libxtst6
diff --git a/src/bin/backlog.c b/src/bin/backlog.c
new file mode 100644
index 0000000..b7271c8
--- /dev/null
+++ b/src/bin/backlog.c
@@ -0,0 +1,226 @@
1#include "private.h"
2#include <Elementary.h>
3#include "termpty.h"
4#include "backlog.h"
5
6
7static int ts_comp = 0;
8static int ts_uncomp = 0;
9static int ts_freeops = 0;
10static Eina_List *ptys = NULL;
11
12static int64_t _mem_used = 0;
13
14static void
15_accounting_change(int64_t diff)
16{
17 if (diff > 0)
18 {
19 diff = ((diff + 16-1) / 16) * 16;
20 }
21 else
22 {
23 diff = ((-1 * diff + 16-1) / 16) * -16;
24 }
25 _mem_used += diff;
26}
27
28int64_t
29termpty_backlog_memory_get(void)
30{
31 return _mem_used;
32}
33
34
35void
36termpty_save_register(Termpty *ty)
37{
38 termpty_backlog_lock();
39 ptys = eina_list_append(ptys, ty);
40 termpty_backlog_unlock();
41}
42
43void
44termpty_save_unregister(Termpty *ty)
45{
46 termpty_backlog_lock();
47 ptys = eina_list_remove(ptys, ty);
48 termpty_backlog_unlock();
49}
50
51Termsave *
52termpty_save_extract(Termsave *ts)
53{
54 if (!ts) return NULL;
55 return ts;
56}
57
58Termsave *
59termpty_save_new(Termpty *ty, Termsave *ts, int w)
60{
61 termpty_save_free(ty, ts);
62
63 Termcell *cells = calloc(1, w * sizeof(Termcell));
64 if (!cells ) return NULL;
65 ts->cells = cells;
66 ts->w = w;
67 _accounting_change(w * sizeof(Termcell));
68 return ts;
69}
70
71Termsave *
72termpty_save_expand(Termpty *ty, Termsave *ts, Termcell *cells, size_t delta)
73{
74 Termcell *newcells;
75
76 newcells = realloc(ts->cells, (ts->w + delta) * sizeof(Termcell));
77 if (!newcells)
78 return NULL;
79
80 memset(newcells + ts->w,
81 0, delta * sizeof(Termcell));
82 TERMPTY_CELL_COPY(ty, cells, &newcells[ts->w], (int)delta);
83
84 _accounting_change(-1 * ts->w * sizeof(Termcell));
85 ts->w += delta;
86 _accounting_change(ts->w * sizeof(Termcell));
87 ts->cells = newcells;
88 return ts;
89}
90
91void
92termpty_save_free(Termpty *ty, Termsave *ts)
93{
94 unsigned int i;
95 if (!ts) return;
96 if (ts->comp) ts_comp--;
97 else ts_uncomp--;
98 ts_freeops++;
99 for (i = 0; i < ts->w; i++)
100 {
101 if (EINA_UNLIKELY(ts->cells[i].att.link_id))
102 term_link_refcount_dec(ty, ts->cells[i].att.link_id, 1);
103 }
104 free(ts->cells);
105 ts->cells = NULL;
106 _accounting_change((-1) * (int)(ts->w * sizeof(Termcell)));
107 ts->w = 0;
108}
109
110void
111termpty_backlog_lock(void)
112{
113}
114
115void
116termpty_backlog_unlock(void)
117{
118}
119
120void
121termpty_backlog_free(Termpty *ty)
122{
123 size_t i;
124
125 if (!ty || !ty->back)
126 return;
127
128 for (i = 0; i < ty->backsize; i++)
129 termpty_save_free(ty, &ty->back[i]);
130 _accounting_change((-1) * (int)(sizeof(Termsave) * ty->backsize));
131 free(ty->back);
132 ty->back = NULL;
133}
134
135void
136termpty_clear_backlog(Termpty *ty)
137{
138 int backsize;
139
140 ty->backlog_beacon.screen_y = 0;
141 ty->backlog_beacon.backlog_y = 0;
142
143 termpty_backlog_lock();
144 termpty_backlog_free(ty);
145 ty->backpos = 0;
146 backsize = ty->backsize;
147 ty->backsize = 0;
148 termpty_backlog_size_set(ty, backsize);
149 termpty_backlog_unlock();
150}
151
152ssize_t
153termpty_backlog_length(Termpty *ty)
154{
155 int backlog_y = ty->backlog_beacon.backlog_y;
156 int screen_y = ty->backlog_beacon.screen_y;
157
158 if (!ty->backsize)
159 return 0;
160
161 for (backlog_y++; backlog_y < (int)ty->backsize; backlog_y++)
162 {
163 int nb_lines;
164 const Termsave *ts;
165
166 ts = BACKLOG_ROW_GET(ty, backlog_y);
167 if (!ts->cells)
168 goto end;
169
170 nb_lines = (ts->w == 0) ? 1 : (ts->w + ty->w - 1) / ty->w;
171 screen_y += nb_lines;
172 ty->backlog_beacon.screen_y = screen_y;
173 ty->backlog_beacon.backlog_y = backlog_y;
174 }
175end:
176 return ty->backlog_beacon.screen_y;
177}
178
179
180void
181termpty_backlog_size_set(Termpty *ty, size_t size)
182{
183 Termsave *new_back;
184 size_t i;
185
186 if (ty->backsize == size)
187 return;
188
189 termpty_backlog_lock();
190
191 if (size == 0)
192 {
193 termpty_backlog_free(ty);
194 goto end;
195 }
196 if (size > ty->backsize)
197 {
198 new_back = realloc(ty->back, sizeof(Termsave) * size);
199 if (!new_back)
200 return;
201 memset(new_back + ty->backsize, 0,
202 sizeof(Termsave) * (size - ty->backsize));
203 ty->back = new_back;
204 }
205 else
206 {
207 new_back = calloc(1, sizeof(Termsave) * size);
208 if (!new_back)
209 return;
210 for (i = 0; i < size; i++)
211 new_back[i] = ty->back[i];
212 for (i = size; i < ty->backsize; i++)
213 termpty_save_free(ty, &ty->back[i]);
214 free(ty->back);
215 ty->back = new_back;
216 }
217 _accounting_change(sizeof(Termsave) * (size - ty->backsize));
218end:
219 ty->backpos = 0;
220 ty->backsize = size;
221 /* Reset beacon */
222 ty->backlog_beacon.screen_y = 0;
223 ty->backlog_beacon.backlog_y = 0;
224
225 termpty_backlog_unlock();
226}
diff --git a/src/bin/backlog.h b/src/bin/backlog.h
new file mode 100644
index 0000000..dfe0fd7
--- /dev/null
+++ b/src/bin/backlog.h
@@ -0,0 +1,30 @@
1#ifndef _BACKLOG_H__
2#define _BACKLOG_H__ 1
3
4void termpty_save_register(Termpty *ty);
5void termpty_save_unregister(Termpty *ty);
6Termsave *termpty_save_extract(Termsave *ts);
7Termsave *termpty_save_new(Termpty *ty, Termsave *ts, int w);
8void termpty_save_free(Termpty *ty, Termsave *ts);
9Termsave *termpty_save_expand(Termpty *ty, Termsave *ts,
10 Termcell *cells, size_t delta);
11
12void termpty_backlog_lock(void);
13void termpty_backlog_unlock(void);
14
15void
16termpty_clear_backlog(Termpty *ty);
17void
18termpty_backlog_free(Termpty *ty);
19void
20termpty_backlog_size_set(Termpty *ty, size_t size);
21ssize_t
22termpty_backlog_length(Termpty *ty);
23
24int64_t
25termpty_backlog_memory_get(void);
26
27#define BACKLOG_ROW_GET(Ty, Y) \
28 (&Ty->back[(Ty->backsize + ty->backpos - ((Y) - 1 )) % Ty->backsize])
29
30#endif
diff --git a/src/bin/config.c b/src/bin/config.c
index 52ff2d2..97e10a9 100644
--- a/src/bin/config.c
+++ b/src/bin/config.c
@@ -216,6 +216,7 @@ config_save(Config *config)
216 char buf[PATH_MAX], buf2[PATH_MAX]; 216 char buf[PATH_MAX], buf2[PATH_MAX];
217 const char *cfgdir; 217 const char *cfgdir;
218 int ok; 218 int ok;
219 Eet_Error err;
219 220
220 EINA_SAFETY_ON_NULL_RETURN(config); 221 EINA_SAFETY_ON_NULL_RETURN(config);
221 222
@@ -236,11 +237,28 @@ config_save(Config *config)
236 snprintf(buf, sizeof(buf), "%s/terminology/config/standard/base.cfg.tmp", cfgdir); 237 snprintf(buf, sizeof(buf), "%s/terminology/config/standard/base.cfg.tmp", cfgdir);
237 snprintf(buf2, sizeof(buf2), "%s/terminology/config/standard/base.cfg", cfgdir); 238 snprintf(buf2, sizeof(buf2), "%s/terminology/config/standard/base.cfg", cfgdir);
238 ef = eet_open(buf, EET_FILE_MODE_WRITE); 239 ef = eet_open(buf, EET_FILE_MODE_WRITE);
239 if (ef) 240 if (!ef)
241 {
242 ERR("error opening file '%s' for writing", buf);
243 return;
244 }
245 ok = eet_data_write(ef, edd_base, CONFIG_KEY, config, 1);
246 if (!ok)
240 { 247 {
241 ok = eet_data_write(ef, edd_base, CONFIG_KEY, config, 1);
242 eet_close(ef); 248 eet_close(ef);
243 if (ok) ecore_file_mv(buf, buf2); 249 ERR("error writing to file '%s'", buf);
250 return;
251 }
252 err = eet_close(ef);
253 if (err != EET_ERROR_NONE)
254 {
255 ERR("error #%d closing file '%s'", err, buf);
256 return;
257 }
258 if (!ecore_file_mv(buf, buf2))
259 {
260 ERR("error moving file '%s' to '%s'", buf, buf2);
261 return;
244 } 262 }
245 main_config_sync(config); 263 main_config_sync(config);
246} 264}
@@ -718,10 +736,12 @@ config_load(void)
718 if (config->version < CONF_VER) 736 if (config->version < CONF_VER)
719 { 737 {
720 // currently no upgrade path so reset config. 738 // currently no upgrade path so reset config.
739 ERR("config is from a newer Terminology, discard it");
721 config_del(config); 740 config_del(config);
722 config = NULL; 741 config = config_new();
742 config->temporary = EINA_TRUE;
723 } 743 }
724 /* do no thing in case the config is from a newer 744 /* do nothing in case the config is from a newer
725 * terminology, we don't want to remove it. */ 745 * terminology, we don't want to remove it. */
726 } 746 }
727 } 747 }
diff --git a/src/bin/controls.c b/src/bin/controls.c
index 279fea3..255eb6b 100644
--- a/src/bin/controls.c
+++ b/src/bin/controls.c
@@ -101,7 +101,7 @@ _cb_ct_new(void *data,
101 void *_event EINA_UNUSED) 101 void *_event EINA_UNUSED)
102{ 102{
103 Controls_Ctx *ctx = data; 103 Controls_Ctx *ctx = data;
104 main_new(ctx->win, ctx->term); 104 main_new(ctx->term);
105} 105}
106 106
107static void 107static void
diff --git a/src/bin/ipc.c b/src/bin/ipc.c
index c9b9ee7..c848e4f 100644
--- a/src/bin/ipc.c
+++ b/src/bin/ipc.c
@@ -1,6 +1,7 @@
1#include "private.h" 1#include "private.h"
2 2
3#include <Ecore.h> 3#include <Ecore.h>
4#include <Ecore_Con.h>
4#include <Ecore_Ipc.h> 5#include <Ecore_Ipc.h>
5#include <Eet.h> 6#include <Eet.h>
6#include "ipc.h" 7#include "ipc.h"
@@ -93,6 +94,8 @@ ipc_init(void)
93 EET_DATA_DESCRIPTOR_ADD_BASIC(new_inst_edd, Ipc_Instance, 94 EET_DATA_DESCRIPTOR_ADD_BASIC(new_inst_edd, Ipc_Instance,
94 "name", name, EET_T_STRING); 95 "name", name, EET_T_STRING);
95 EET_DATA_DESCRIPTOR_ADD_BASIC(new_inst_edd, Ipc_Instance, 96 EET_DATA_DESCRIPTOR_ADD_BASIC(new_inst_edd, Ipc_Instance,
97 "theme", theme, EET_T_STRING);
98 EET_DATA_DESCRIPTOR_ADD_BASIC(new_inst_edd, Ipc_Instance,
96 "role", role, EET_T_STRING); 99 "role", role, EET_T_STRING);
97 EET_DATA_DESCRIPTOR_ADD_BASIC(new_inst_edd, Ipc_Instance, 100 EET_DATA_DESCRIPTOR_ADD_BASIC(new_inst_edd, Ipc_Instance,
98 "title", title, EET_T_STRING); 101 "title", title, EET_T_STRING);
@@ -128,6 +131,16 @@ ipc_init(void)
128 "hold", hold, EET_T_INT); 131 "hold", hold, EET_T_INT);
129 EET_DATA_DESCRIPTOR_ADD_BASIC(new_inst_edd, Ipc_Instance, 132 EET_DATA_DESCRIPTOR_ADD_BASIC(new_inst_edd, Ipc_Instance,
130 "nowm", nowm, EET_T_INT); 133 "nowm", nowm, EET_T_INT);
134 EET_DATA_DESCRIPTOR_ADD_BASIC(new_inst_edd, Ipc_Instance,
135 "xterm_256color", xterm_256color, EET_T_INT);
136 EET_DATA_DESCRIPTOR_ADD_BASIC(new_inst_edd, Ipc_Instance,
137 "active_links", active_links, EET_T_INT);
138 EET_DATA_DESCRIPTOR_ADD_BASIC(new_inst_edd, Ipc_Instance,
139 "video_mute", active_links, EET_T_INT);
140 EET_DATA_DESCRIPTOR_ADD_BASIC(new_inst_edd, Ipc_Instance,
141 "cursor_blink", active_links, EET_T_INT);
142 EET_DATA_DESCRIPTOR_ADD_BASIC(new_inst_edd, Ipc_Instance,
143 "visual_bell", active_links, EET_T_INT);
131} 144}
132 145
133Eina_Bool 146Eina_Bool
@@ -171,6 +184,19 @@ ipc_instance_new_func_set(void (*func) (Ipc_Instance *inst))
171 func_new_inst = func; 184 func_new_inst = func;
172} 185}
173 186
187void
188ipc_instance_conn_free(void)
189{
190 char *hash = _ipc_hash_get();
191 char *address = ecore_con_local_path_new(EINA_FALSE,
192 hash,
193 0);
194 errno = 0;
195 unlink(address);
196 ERR("unlinking: '%s': %s", address, strerror(errno));
197 free(address);
198}
199
174Eina_Bool 200Eina_Bool
175ipc_instance_add(Ipc_Instance *inst) 201ipc_instance_add(Ipc_Instance *inst)
176{ 202{
@@ -178,7 +204,7 @@ ipc_instance_add(Ipc_Instance *inst)
178 void *data; 204 void *data;
179 char *hash = _ipc_hash_get(); 205 char *hash = _ipc_hash_get();
180 Ecore_Ipc_Server *ipcsrv; 206 Ecore_Ipc_Server *ipcsrv;
181 207
182 if (!hash) return EINA_FALSE; 208 if (!hash) return EINA_FALSE;
183 data = eet_data_descriptor_encode(new_inst_edd, inst, &size); 209 data = eet_data_descriptor_encode(new_inst_edd, inst, &size);
184 if (!data) 210 if (!data)
@@ -186,6 +212,7 @@ ipc_instance_add(Ipc_Instance *inst)
186 free(hash); 212 free(hash);
187 return EINA_FALSE; 213 return EINA_FALSE;
188 } 214 }
215
189 ipcsrv = ecore_ipc_server_connect(ECORE_IPC_LOCAL_USER, hash, 0, NULL); 216 ipcsrv = ecore_ipc_server_connect(ECORE_IPC_LOCAL_USER, hash, 0, NULL);
190 if (ipcsrv) 217 if (ipcsrv)
191 { 218 {
@@ -196,6 +223,10 @@ ipc_instance_add(Ipc_Instance *inst)
196 ecore_ipc_server_del(ipcsrv); 223 ecore_ipc_server_del(ipcsrv);
197 return EINA_TRUE; 224 return EINA_TRUE;
198 } 225 }
226 else
227 {
228 DBG("connect failed");
229 }
199 free(data); 230 free(data);
200 free(hash); 231 free(hash);
201 return EINA_FALSE; 232 return EINA_FALSE;
diff --git a/src/bin/ipc.h b/src/bin/ipc.h
index 4ade907..0aa4775 100644
--- a/src/bin/ipc.h
+++ b/src/bin/ipc.h
@@ -7,28 +7,33 @@ typedef struct _Ipc_Instance Ipc_Instance;
7 7
8struct _Ipc_Instance 8struct _Ipc_Instance
9{ 9{
10 const char *cmd; 10 char *cmd;
11 const char *cd; 11 char *cd;
12 const char *background; 12 char *background;
13 const char *name; 13 char *name;
14 const char *role; 14 char *theme;
15 const char *title; 15 char *role;
16 const char *icon_name; 16 char *title;
17 const char *font; 17 char *icon_name;
18 const char *startup_id; 18 char *font;
19 const char *startup_split; 19 char *startup_id;
20 char *startup_split;
20 int x, y, w, h; 21 int x, y, w, h;
21 int pos; 22 Eina_Bool pos;
22 int login_shell; 23 Eina_Bool login_shell;
23 int fullscreen; 24 Eina_Bool fullscreen;
24 int iconic; 25 Eina_Bool iconic;
25 int borderless; 26 Eina_Bool borderless;
26 int override; 27 Eina_Bool override;
27 int maximized; 28 Eina_Bool maximized;
28 int hold; 29 Eina_Bool hold;
29 int nowm; 30 Eina_Bool nowm;
30 int xterm_256color; 31 Eina_Bool xterm_256color;
31 int active_links; 32 Eina_Bool video_mute;
33 Eina_Bool active_links;
34 Eina_Bool cursor_blink;
35 Eina_Bool visual_bell;
36 Config *config;
32}; 37};
33 38
34void ipc_init(void); 39void ipc_init(void);
@@ -36,5 +41,6 @@ void ipc_shutdown(void);
36Eina_Bool ipc_serve(void); 41Eina_Bool ipc_serve(void);
37void ipc_instance_new_func_set(void (*func) (Ipc_Instance *inst)); 42void ipc_instance_new_func_set(void (*func) (Ipc_Instance *inst));
38Eina_Bool ipc_instance_add(Ipc_Instance *inst); 43Eina_Bool ipc_instance_add(Ipc_Instance *inst);
44void ipc_instance_conn_free(void);
39 45
40#endif 46#endif
diff --git a/src/bin/main.c b/src/bin/main.c
index b50dbbe..9bcd88b 100644
--- a/src/bin/main.c
+++ b/src/bin/main.c
@@ -27,6 +27,129 @@ Eina_Bool multisense_available = EINA_TRUE;
27static Config *_main_config = NULL; 27static Config *_main_config = NULL;
28 28
29static void 29static void
30_set_instance_theme(Ipc_Instance *inst)
31{
32 char path[PATH_MAX];
33 char theme_name[PATH_MAX];
34 const char *theme_path = (const char *)&path;
35
36 if (!inst->theme)
37 return;
38
39 if (eina_str_has_suffix(inst->theme, ".edj"))
40 eina_strlcpy(theme_name, inst->theme, sizeof(theme_name));
41 else
42 snprintf(theme_name, sizeof(theme_name), "%s.edj", inst->theme);
43
44 if (strchr(theme_name, '/'))
45 eina_strlcpy(path, theme_name, sizeof(path));
46 else
47 theme_path = theme_path_get(theme_name);
48
49 eina_stringshare_replace(&(inst->config->theme), theme_path);
50 inst->config->temporary = EINA_TRUE;
51}
52
53static void
54_configure_instance(Ipc_Instance *inst)
55{
56 Config *config = inst->config;
57
58 _set_instance_theme(inst);
59
60 if (inst->background)
61 {
62 eina_stringshare_replace(&(config->background), inst->background);
63 config->temporary = EINA_TRUE;
64 }
65
66 if (inst->font)
67 {
68 char *p = strchr(inst->font, '/');
69 if (p)
70 {
71 int sz;
72 char *fname = alloca(p - inst->font + 1);
73
74 strncpy(fname, inst->font, p - inst->font);
75 fname[p - inst->font] = '\0';
76 sz = atoi(p+1);
77 if (sz > 0)
78 inst->config->font.size = sz;
79 eina_stringshare_replace(&(inst->config->font.name), fname);
80 inst->config->font.bitmap = EINA_FALSE;
81 }
82 else
83 {
84 char buf[4096], *file;
85 Eina_List *files;
86 int n = strlen(inst->font);
87 Eina_Bool found = EINA_FALSE;
88
89 snprintf(buf, sizeof(buf), "%s/fonts", elm_app_data_dir_get());
90 files = ecore_file_ls(buf);
91 EINA_LIST_FREE(files, file)
92 {
93 if (n > 0)
94 {
95 if (!strncasecmp(file, inst->font, n))
96 {
97 n = -1;
98 eina_stringshare_replace(&(inst->config->font.name), file);
99 inst->config->font.bitmap = EINA_TRUE;
100 found = EINA_TRUE;
101 }
102 }
103 free(file);
104 }
105 if (!found)
106 {
107 ERR("font '%s' not found in %s", inst->font, buf);
108 }
109 }
110 config->font_set = EINA_TRUE;
111 config->temporary = EINA_TRUE;
112 }
113
114 if (inst->login_shell != 0xff)
115 {
116 inst->config->login_shell = inst->login_shell;
117 inst->config->temporary = EINA_TRUE;
118 }
119 inst->login_shell = inst->config->login_shell;
120
121 if (inst->xterm_256color)
122 {
123 inst->config->xterm_256color = EINA_TRUE;
124 inst->config->temporary = EINA_TRUE;
125 }
126 if (inst->video_mute != 0xff)
127 {
128 config->mute = inst->video_mute;
129 config->temporary = EINA_TRUE;
130 }
131 if (inst->cursor_blink != 0xff)
132 {
133 config->disable_cursor_blink = !inst->cursor_blink;
134 config->temporary = EINA_TRUE;
135 }
136 if (inst->visual_bell != 0xff)
137 {
138 config->disable_visual_bell = !inst->visual_bell;
139 config->temporary = EINA_TRUE;
140 }
141 if (inst->active_links != 0xff)
142 {
143 config->active_links = !!inst->active_links;
144 config->active_links_email = inst->config->active_links;
145 config->active_links_file = inst->config->active_links;
146 config->active_links_url = inst->config->active_links;
147 config->active_links_escape = inst->config->active_links;
148 config->temporary = EINA_TRUE;
149 }
150}
151
152static void
30_check_multisense(void) 153_check_multisense(void)
31{ 154{
32 int enabled; 155 int enabled;
@@ -70,7 +193,7 @@ main_ipc_new(Ipc_Instance *inst)
70 char buf[4096]; 193 char buf[4096];
71 194
72 snprintf(buf, sizeof(buf), "DESKTOP_STARTUP_ID=%s", inst->startup_id); 195 snprintf(buf, sizeof(buf), "DESKTOP_STARTUP_ID=%s", inst->startup_id);
73 putenv(buf); 196 putenv(strdup(buf));
74 } 197 }
75 ecore_app_args_get(&pargc, &pargv); 198 ecore_app_args_get(&pargc, &pargv);
76 nargc = 1; 199 nargc = 1;
@@ -93,7 +216,11 @@ main_ipc_new(Ipc_Instance *inst)
93 if (inst->nowm) nargc += 1; 216 if (inst->nowm) nargc += 1;
94 if (inst->xterm_256color) nargc += 1; 217 if (inst->xterm_256color) nargc += 1;
95 if (inst->active_links) nargc += 1; 218 if (inst->active_links) nargc += 1;
219 if (inst->video_mute) nargc += 1;
220 if (inst->cursor_blink) nargc += 1;
221 if (inst->visual_bell) nargc += 1;
96 if (inst->cmd) nargc += 2; 222 if (inst->cmd) nargc += 2;
223 if (inst->theme) nargc += 2;
97 224
98 nargv = calloc(nargc + 1, sizeof(char *)); 225 nargv = calloc(nargc + 1, sizeof(char *));
99 if (!nargv) return; 226 if (!nargv) return;
@@ -115,6 +242,11 @@ main_ipc_new(Ipc_Instance *inst)
115 nargv[i++] = "-n"; 242 nargv[i++] = "-n";
116 nargv[i++] = (char *)inst->name; 243 nargv[i++] = (char *)inst->name;
117 } 244 }
245 if (inst->theme)
246 {
247 nargv[i++] = "-t";
248 nargv[i++] = (char *)inst->theme;
249 }
118 if (inst->role) 250 if (inst->role)
119 { 251 {
120 nargv[i++] = "-r"; 252 nargv[i++] = "-r";
@@ -232,6 +364,19 @@ main_ipc_new(Ipc_Instance *inst)
232 nargv[i++] = "-e"; 364 nargv[i++] = "-e";
233 nargv[i++] = (char *)inst->cmd; 365 nargv[i++] = (char *)inst->cmd;
234 } 366 }
367 if (inst->video_mute)
368 {
369 nargv[i++] = "-m";
370 }
371 if (inst->cursor_blink)
372 {
373 nargv[i++] = "-c";
374 }
375 if (inst->visual_bell)
376 {
377 nargv[i++] = "-G";
378 }
379
235 380
236 ecore_app_args_set(nargc, (const char **)nargv); 381 ecore_app_args_set(nargc, (const char **)nargv);
237 wn = win_new(inst->name, inst->role, inst->title, inst->icon_name, 382 wn = win_new(inst->name, inst->role, inst->title, inst->icon_name,
@@ -247,60 +392,9 @@ main_ipc_new(Ipc_Instance *inst)
247 392
248 win = win_evas_object_get(wn); 393 win = win_evas_object_get(wn);
249 config = win_config_get(wn); 394 config = win_config_get(wn);
395 inst->config = config;
250 396
251 unsetenv("DESKTOP_STARTUP_ID"); 397 _configure_instance(inst);
252 if (inst->background)
253 {
254 eina_stringshare_replace(&(config->background), inst->background);
255 config->temporary = EINA_TRUE;
256 }
257
258 if (inst->font)
259 {
260 if (strchr(inst->font, '/'))
261 {
262 char *fname = alloca(strlen(inst->font) + 1);
263 char *p;
264
265 strcpy(fname, inst->font);
266 p = strrchr(fname, '/');
267 if (p)
268 {
269 int sz;
270
271 *p = 0;
272 p++;
273 sz = atoi(p);
274 if (sz > 0) config->font.size = sz;
275 eina_stringshare_replace(&(config->font.name), fname);
276 }
277 config->font.bitmap = 0;
278 }
279 else
280 {
281 char buf[4096], *file;
282 Eina_List *files;
283 int n = strlen(inst->font);
284
285 snprintf(buf, sizeof(buf), "%s/fonts", elm_app_data_dir_get());
286 files = ecore_file_ls(buf);
287 EINA_LIST_FREE(files, file)
288 {
289 if (n > 0)
290 {
291 if (!strncasecmp(file, inst->font, n))
292 {
293 n = -1;
294 eina_stringshare_replace(&(config->font.name), file);
295 config->font.bitmap = 1;
296 }
297 }
298 free(file);
299 }
300 }
301 config->font_set = EINA_TRUE;
302 config->temporary = EINA_TRUE;
303 }
304 398
305 if (inst->w <= 0) inst->w = 80; 399 if (inst->w <= 0) inst->w = 80;
306 if (inst->h <= 0) inst->h = 24; 400 if (inst->h <= 0) inst->h = 24;
@@ -337,6 +431,7 @@ main_ipc_new(Ipc_Instance *inst)
337 (ecore_evas_ecore_evas_get(evas_object_evas_get(win)), 1); 431 (ecore_evas_ecore_evas_get(evas_object_evas_get(win)), 1);
338 ecore_app_args_set(pargc, (const char **)pargv); 432 ecore_app_args_set(pargc, (const char **)pargv);
339 free(nargv); 433 free(nargv);
434 unsetenv("DESKTOP_STARTUP_ID");
340} 435}
341 436
342static const char *emotion_choices[] = { 437static const char *emotion_choices[] = {
@@ -468,65 +563,278 @@ _log_void(const Eina_Log_Domain *_d EINA_UNUSED,
468} 563}
469#endif 564#endif
470 565
566static void
567_start(Ipc_Instance *instance)
568{
569 Win *wn;
570 Evas_Object *win;
571 Term *term;
572 Config *config;
573
574 wn = win_new(instance->name, instance->role, instance->title,
575 instance->icon_name, instance->config,
576 instance->fullscreen, instance->iconic, instance->borderless,
577 instance->override, instance->maximized);
578 // set an env so terminal apps can detect they are in terminology :)
579 putenv("TERMINOLOGY=1");
580
581 config_del(instance->config);
582 config = NULL;
583 if (!wn)
584 {
585 CRITICAL(_("Could not create window."));
586 goto exit;
587 }
588
589 config = win_config_get(wn);
590
591 term = term_new(wn, config, instance->cmd, instance->login_shell,
592 instance->cd,
593 instance->w, instance->h, instance->hold, instance->title);
594 if (!term)
595 {
596 CRITICAL(_("Could not create terminal widget."));
597 config = NULL;
598 goto exit;
599 }
600
601 if (win_term_set(wn, term) < 0)
602 {
603 goto exit;
604 }
605
606 main_trans_update(config);
607 main_media_update(config);
608 win_sizing_handle(wn);
609 win = win_evas_object_get(wn);
610 evas_object_show(win);
611 if (instance->startup_split)
612 {
613 unsigned int i = 0;
614 Eina_List *cmds_list = NULL;
615 Term *next = term;
616
617 for (i = 0; i < strlen(instance->startup_split); i++)
618 {
619 char *cmd = NULL;
620
621 if (instance->startup_split[i] == 'v')
622 {
623 cmd = cmds_list ? cmds_list->data : NULL;
624 split_vertically(win_evas_object_get(term_win_get(next)),
625 term_termio_get(next), cmd);
626 cmds_list = eina_list_remove_list(cmds_list, cmds_list);
627 }
628 else if (instance->startup_split[i] == 'h')
629 {
630 cmd = cmds_list ? cmds_list->data : NULL;
631 split_horizontally(win_evas_object_get(term_win_get(next)),
632 term_termio_get(next), cmd);
633 cmds_list = eina_list_remove_list(cmds_list, cmds_list);
634 }
635 else if (instance->startup_split[i] == '-')
636 next = term_next_get(next);
637 else
638 {
639 CRITICAL(_("invalid argument found for option -S/--split."
640 " See --help."));
641 goto end;
642 }
643 }
644 if (cmds_list)
645 eina_list_free(cmds_list);
646 }
647 if (instance->pos)
648 {
649 int screen_w, screen_h;
650
651 elm_win_screen_size_get(win, NULL, NULL, &screen_w, &screen_h);
652 if (instance->x < 0) instance->x = screen_w + instance->x;
653 if (instance->y < 0) instance->y = screen_h + instance->y;
654 evas_object_move(win, instance->x, instance->y);
655 }
656 if (instance->nowm)
657 ecore_evas_focus_set(ecore_evas_ecore_evas_get(
658 evas_object_evas_get(win)), 1);
659
660 controls_init();
661
662 win_scale_wizard(win, term);
663
664 terminology_starting_up = EINA_FALSE;
665
666
667end:
668 return;
669exit:
670 ecore_main_loop_quit();
671}
672
673struct Instance_Add {
674 Ipc_Instance *instance;
675 char **argv;
676 Eina_Bool result;
677 Eina_Bool timedout;
678 Eina_Bool done;
679 pthread_mutex_t lock;
680};
681
682static void
683_instance_add_free(struct Instance_Add *add)
684{
685 if (!add)
686 return;
687
688 pthread_mutex_destroy(&add->lock);
689 free(add);
690}
691
692
693static void *
694_instance_sleep(void *data)
695{
696 struct Instance_Add *add = data;
697 Eina_Bool timedout = EINA_FALSE;
698
699 sleep(2);
700 pthread_mutex_lock(&add->lock);
701 if (!add->done)
702 timedout = add->timedout = EINA_TRUE;
703 pthread_mutex_unlock(&add->lock);
704 if (timedout)
705 {
706 /* ok, we waited 2 seconds without any answer,
707 * remove the unix socket and restart terminology from scratch in a
708 * better state */
709 ipc_instance_conn_free();
710 errno = 0;
711 execv(add->argv[0], add->argv);
712 ERR("execv failed on '%s': %s", add->argv[0], strerror(errno));
713 }
714 else
715 {
716 _instance_add_free(add);
717 }
718
719 return NULL;
720}
721
722static Eina_Bool
723_instance_add_waiter(Ipc_Instance *instance,
724 char **argv)
725{
726 struct Instance_Add *add;
727 Eina_Bool timedout = EINA_FALSE;
728 Eina_Bool result = EINA_TRUE;
729 pthread_t thr;
730
731 add = calloc(1, sizeof(*add));
732 if (!add)
733 return EINA_FALSE;
734
735 add->instance = instance;
736 add->argv = argv;
737 pthread_mutex_init(&add->lock, NULL);
738
739 pthread_create(&thr, NULL, &_instance_sleep, add);
740
741 /* If the unix socket is stalled, this might block */
742 result = ipc_instance_add(add->instance);
743 pthread_mutex_lock(&add->lock);
744 /* Hoora, it did not block! */
745 add->done = EINA_TRUE;
746 if (add->timedout)
747 {
748 timedout = add->timedout = EINA_TRUE;
749 result = EINA_FALSE;
750 }
751 pthread_mutex_unlock(&add->lock);
752 if (timedout)
753 _instance_add_free(add);
754
755 return result;
756}
757
758static Eina_Bool
759_start_multi(Ipc_Instance *instance,
760 char **argv)
761{
762 int remote_try = 0;
763 do
764 {
765 if (_instance_add_waiter(instance, argv))
766 {
767 goto exit;
768 }
769 /* Could not start a new window remotely,
770 * let's start our own server */
771 ipc_instance_new_func_set(main_ipc_new);
772 if (ipc_serve())
773 {
774 goto normal_start;
775 }
776 else
777 {
778 DBG("IPC server: failure");
779 }
780 remote_try++;
781 }
782 while (remote_try <= 1);
783
784normal_start:
785 _start(instance);
786 return EINA_FALSE;
787
788exit:
789 return EINA_TRUE;
790}
791
471EAPI_MAIN int 792EAPI_MAIN int
472elm_main(int argc, char **argv) 793elm_main(int argc, char **argv)
473{ 794{
474 char *cmd = NULL;
475 char *cd = NULL;
476 char *theme = NULL;
477 char *background = NULL;
478 char *geometry = NULL; 795 char *geometry = NULL;
479 char *name = NULL;
480 char *role = NULL;
481 char *title = NULL;
482 char *icon_name = NULL;
483 char *font = NULL;
484 char *startup_split = NULL;
485 char *video_module = NULL; 796 char *video_module = NULL;
486 Eina_Bool login_shell = 0xff; /* unset */
487 Eina_Bool video_mute = 0xff; /* unset */
488 Eina_Bool cursor_blink = 0xff; /* unset */
489 Eina_Bool visual_bell = 0xff; /* unset */
490 Eina_Bool active_links = 0xff; /* unset */
491 Eina_Bool fullscreen = EINA_FALSE;
492 Eina_Bool iconic = EINA_FALSE;
493 Eina_Bool borderless = EINA_FALSE;
494 Eina_Bool override = EINA_FALSE;
495 Eina_Bool maximized = EINA_FALSE;
496 Eina_Bool nowm = EINA_FALSE;
497 Eina_Bool quit_option = EINA_FALSE; 797 Eina_Bool quit_option = EINA_FALSE;
498 Eina_Bool hold = EINA_FALSE;
499 Eina_Bool single = EINA_FALSE; 798 Eina_Bool single = EINA_FALSE;
500 Eina_Bool cmd_options = EINA_FALSE; 799 Eina_Bool cmd_options = EINA_FALSE;
501 Eina_Bool xterm_256color = EINA_FALSE; 800 Ipc_Instance instance = {
801 .login_shell = 0xff, /* unset */
802 .active_links = 0xff, /* unset */
803 .video_mute = 0xff, /* unset */
804 .cursor_blink = 0xff, /* unset */
805 .visual_bell = 0xff, /* unset */
806 .startup_id = getenv("DESKTOP_STARTUP_ID"),
807 .w = 1,
808 .h = 1,
809 };
502 Ecore_Getopt_Value values[] = { 810 Ecore_Getopt_Value values[] = {
503 ECORE_GETOPT_VALUE_BOOL(cmd_options), 811 ECORE_GETOPT_VALUE_BOOL(cmd_options),
504 ECORE_GETOPT_VALUE_STR(cd), 812 ECORE_GETOPT_VALUE_STR(instance.cd),
505 ECORE_GETOPT_VALUE_STR(theme), 813 ECORE_GETOPT_VALUE_STR(instance.theme),
506 ECORE_GETOPT_VALUE_STR(background), 814 ECORE_GETOPT_VALUE_STR(instance.background),
507 ECORE_GETOPT_VALUE_STR(geometry), 815 ECORE_GETOPT_VALUE_STR(geometry),
508 ECORE_GETOPT_VALUE_STR(name), 816 ECORE_GETOPT_VALUE_STR(instance.name),
509 ECORE_GETOPT_VALUE_STR(role), 817 ECORE_GETOPT_VALUE_STR(instance.role),
510 ECORE_GETOPT_VALUE_STR(title), 818 ECORE_GETOPT_VALUE_STR(instance.title),
511 ECORE_GETOPT_VALUE_STR(icon_name), 819 ECORE_GETOPT_VALUE_STR(instance.icon_name),
512 ECORE_GETOPT_VALUE_STR(font), 820 ECORE_GETOPT_VALUE_STR(instance.font),
513 ECORE_GETOPT_VALUE_STR(startup_split), 821 ECORE_GETOPT_VALUE_STR(instance.startup_split),
514 ECORE_GETOPT_VALUE_STR(video_module), 822 ECORE_GETOPT_VALUE_STR(video_module),
515 823
516 ECORE_GETOPT_VALUE_BOOL(login_shell), 824 ECORE_GETOPT_VALUE_BOOL(instance.login_shell),
517 ECORE_GETOPT_VALUE_BOOL(video_mute), 825 ECORE_GETOPT_VALUE_BOOL(instance.video_mute),
518 ECORE_GETOPT_VALUE_BOOL(cursor_blink), 826 ECORE_GETOPT_VALUE_BOOL(instance.cursor_blink),
519 ECORE_GETOPT_VALUE_BOOL(visual_bell), 827 ECORE_GETOPT_VALUE_BOOL(instance.visual_bell),
520 ECORE_GETOPT_VALUE_BOOL(fullscreen), 828 ECORE_GETOPT_VALUE_BOOL(instance.fullscreen),
521 ECORE_GETOPT_VALUE_BOOL(iconic), 829 ECORE_GETOPT_VALUE_BOOL(instance.iconic),
522 ECORE_GETOPT_VALUE_BOOL(borderless), 830 ECORE_GETOPT_VALUE_BOOL(instance.borderless),
523 ECORE_GETOPT_VALUE_BOOL(override), 831 ECORE_GETOPT_VALUE_BOOL(instance.override),
524 ECORE_GETOPT_VALUE_BOOL(maximized), 832 ECORE_GETOPT_VALUE_BOOL(instance.maximized),
525 ECORE_GETOPT_VALUE_BOOL(nowm), 833 ECORE_GETOPT_VALUE_BOOL(instance.nowm),
526 ECORE_GETOPT_VALUE_BOOL(hold), 834 ECORE_GETOPT_VALUE_BOOL(instance.hold),
527 ECORE_GETOPT_VALUE_BOOL(single), 835 ECORE_GETOPT_VALUE_BOOL(single),
528 ECORE_GETOPT_VALUE_BOOL(xterm_256color), 836 ECORE_GETOPT_VALUE_BOOL(instance.xterm_256color),
529 ECORE_GETOPT_VALUE_BOOL(active_links), 837 ECORE_GETOPT_VALUE_BOOL(instance.active_links),
530 838
531 ECORE_GETOPT_VALUE_BOOL(quit_option), 839 ECORE_GETOPT_VALUE_BOOL(quit_option),
532 ECORE_GETOPT_VALUE_BOOL(quit_option), 840 ECORE_GETOPT_VALUE_BOOL(quit_option),
@@ -535,16 +843,8 @@ elm_main(int argc, char **argv)
535 843
536 ECORE_GETOPT_VALUE_NONE 844 ECORE_GETOPT_VALUE_NONE
537 }; 845 };
538 Win *wn;
539 Term *term;
540 Config *config = NULL;
541 Evas_Object *win;
542 int args, retval = EXIT_SUCCESS; 846 int args, retval = EXIT_SUCCESS;
543 int remote_try = 0; 847 Eina_Bool size_set = EINA_FALSE;
544 int pos_set = 0, size_set = 0;
545 int pos_x = 0, pos_y = 0;
546 int size_w = 1, size_h = 1;
547 Eina_List *cmds_list = NULL;
548 848
549 terminology_starting_up = EINA_TRUE; 849 terminology_starting_up = EINA_TRUE;
550 850
@@ -590,9 +890,12 @@ elm_main(int argc, char **argv)
590 goto end; 890 goto end;
591 } 891 }
592 892
893 ecore_con_init();
894 ecore_con_url_init();
895
593 ipc_init(); 896 ipc_init();
594 897
595 config = config_fork(_main_config); 898 instance.config = config_fork(_main_config);
596 899
597 args = ecore_getopt_parse(&options, values, argc, argv); 900 args = ecore_getopt_parse(&options, values, argc, argv);
598 if (args < 0) 901 if (args < 0)
@@ -606,6 +909,7 @@ elm_main(int argc, char **argv)
606 909
607 if (cmd_options) 910 if (cmd_options)
608 { 911 {
912 Eina_List *cmds_list = NULL;
609 int i; 913 int i;
610 914
611 if (args == argc) 915 if (args == argc)
@@ -615,11 +919,11 @@ elm_main(int argc, char **argv)
615 goto end; 919 goto end;
616 } 920 }
617 921
618 if (startup_split) 922 if (instance.startup_split)
619 { 923 {
620 for(i = args+1; i < argc; i++) 924 for(i = args+1; i < argc; i++)
621 cmds_list = eina_list_append(cmds_list, argv[i]); 925 cmds_list = eina_list_append(cmds_list, argv[i]);
622 cmd = argv[args]; 926 instance.cmd = argv[args];
623 } 927 }
624 else 928 else
625 { 929 {
@@ -631,86 +935,15 @@ elm_main(int argc, char **argv)
631 eina_strbuf_append_char(strb, ' '); 935 eina_strbuf_append_char(strb, ' ');
632 eina_strbuf_append(strb, argv[i]); 936 eina_strbuf_append(strb, argv[i]);
633 } 937 }
634 cmd = eina_strbuf_string_steal(strb); 938 instance.cmd = eina_strbuf_string_steal(strb);
635 eina_strbuf_free(strb); 939 eina_strbuf_free(strb);
636 } 940 }
637 } 941 }
638 942
639 _check_multisense(); 943 _check_multisense();
640 944
641 if (theme) 945 _configure_instance(&instance);
642 {
643 char path[PATH_MAX];
644 char theme_name[PATH_MAX];
645 const char *theme_path = (const char *)&path;
646
647 if (eina_str_has_suffix(theme, ".edj"))
648 eina_strlcpy(theme_name, theme, sizeof(theme_name));
649 else
650 snprintf(theme_name, sizeof(theme_name), "%s.edj", theme);
651
652 if (strchr(theme_name, '/'))
653 eina_strlcpy(path, theme_name, sizeof(path));
654 else
655 theme_path = theme_path_get(theme_name);
656 946
657 eina_stringshare_replace(&(config->theme), theme_path);
658 config->temporary = EINA_TRUE;
659 }
660
661 if (background)
662 {
663 eina_stringshare_replace(&(config->background), background);
664 config->temporary = EINA_TRUE;
665 }
666
667 if (font)
668 {
669 char *p = strchr(font, '/');
670 if (p)
671 {
672 int sz;
673 char *fname = alloca(p - font + 1);
674
675 strncpy(fname, font, p - font);
676 fname[p - font] = '\0';
677 sz = atoi(p+1);
678 if (sz > 0) config->font.size = sz;
679 eina_stringshare_replace(&(config->font.name), fname);
680 config->font.bitmap = 0;
681 config->font_set = 1;
682 }
683 else
684 {
685 char buf[4096], *file;
686 Eina_List *files;
687 int n = strlen(font);
688 Eina_Bool found = EINA_FALSE;
689
690 snprintf(buf, sizeof(buf), "%s/fonts", elm_app_data_dir_get());
691 files = ecore_file_ls(buf);
692 EINA_LIST_FREE(files, file)
693 {
694 if (n > 0)
695 {
696 if (!strncasecmp(file, font, n))
697 {
698 n = -1;
699 eina_stringshare_replace(&(config->font.name), file);
700 config->font.bitmap = 1;
701 config->font_set = 1;
702 found = EINA_TRUE;
703 }
704 }
705 free(file);
706 }
707 if (!found)
708 {
709 ERR("font '%s' not found in %s", font, buf);
710 }
711 }
712 config->temporary = EINA_TRUE;
713 }
714 947
715 if (video_module) 948 if (video_module)
716 { 949 {
@@ -723,270 +956,109 @@ elm_main(int argc, char **argv)
723 956
724 if (i == EINA_C_ARRAY_LENGTH(emotion_choices)) 957 if (i == EINA_C_ARRAY_LENGTH(emotion_choices))
725 i = 0; /* ecore getopt shouldn't let this happen, but... */ 958 i = 0; /* ecore getopt shouldn't let this happen, but... */
726 config->vidmod = i; 959 instance.config->vidmod = i;
727 config->temporary = EINA_TRUE; 960 instance.config->temporary = EINA_TRUE;
728 } 961 }
729 962
730 if (video_mute != 0xff)
731 {
732 config->mute = video_mute;
733 config->temporary = EINA_TRUE;
734 }
735 if (cursor_blink != 0xff)
736 {
737 config->disable_cursor_blink = !cursor_blink;
738 config->temporary = EINA_TRUE;
739 }
740 if (visual_bell != 0xff)
741 {
742 config->disable_visual_bell = !visual_bell;
743 config->temporary = EINA_TRUE;
744 }
745 if (active_links != 0xff)
746 {
747 config->active_links = !!active_links;
748 config->active_links_email = config->active_links;
749 config->active_links_file = config->active_links;
750 config->active_links_url = config->active_links;
751 config->active_links_escape = config->active_links;
752 config->temporary = EINA_TRUE;
753 }
754
755 if (xterm_256color)
756 {
757 config->xterm_256color = EINA_TRUE;
758 config->temporary = EINA_TRUE;
759 }
760 963
761 if (geometry) 964 if (geometry)
762 { 965 {
763 if (sscanf(geometry,"%ix%i+%i+%i", &size_w, &size_h, &pos_x, &pos_y) == 4) 966 if (sscanf(geometry,"%ix%i+%i+%i", &instance.w, &instance.h,
967 &instance.x, &instance.y) == 4)
764 { 968 {
765 pos_set = 1; 969 instance.pos = EINA_TRUE;
766 size_set = 1; 970 size_set = EINA_TRUE;
767 } 971 }
768 else if (sscanf(geometry,"%ix%i-%i+%i", &size_w, &size_h, &pos_x, &pos_y) == 4) 972 else if (sscanf(geometry,"%ix%i-%i+%i", &instance.w, &instance.h,
973 &instance.x, &instance.y) == 4)
769 { 974 {
770 pos_x = -pos_x; 975 instance.x = -instance.x;
771 pos_set = 1; 976 instance.pos = EINA_TRUE;
772 size_set = 1; 977 size_set = EINA_TRUE;
773 } 978 }
774 else if (sscanf(geometry,"%ix%i-%i-%i", &size_w, &size_h, &pos_x, &pos_y) == 4) 979 else if (sscanf(geometry,"%ix%i-%i-%i", &instance.w, &instance.h,
980 &instance.x, &instance.y) == 4)
775 { 981 {
776 pos_x = -pos_x; 982 instance.x = -instance.x;
777 pos_y = -pos_y; 983 instance.y = -instance.y;
778 pos_set = 1; 984 instance.pos = EINA_TRUE;
779 size_set = 1; 985 size_set = EINA_TRUE;
780 } 986 }
781 else if (sscanf(geometry,"%ix%i+%i-%i", &size_w, &size_h, &pos_x, &pos_y) == 4) 987 else if (sscanf(geometry,"%ix%i+%i-%i", &instance.w, &instance.h,
988 &instance.x, &instance.y) == 4)
782 { 989 {
783 pos_y = -pos_y; 990 instance.y = -instance.y;
784 pos_set = 1; 991 instance.pos = EINA_TRUE;
785 size_set = 1; 992 size_set = EINA_TRUE;
786 } 993 }
787 else if (sscanf(geometry,"%ix%i", &size_w, &size_h) == 2) 994 else if (sscanf(geometry,"%ix%i", &instance.w, &instance.h) == 2)
788 { 995 {
789 size_set = 1; 996 size_set = EINA_TRUE;
790 } 997 }
791 else if (sscanf(geometry,"+%i+%i", &pos_x, &pos_y) == 2) 998 else if (sscanf(geometry,"+%i+%i", &instance.x, &instance.y) == 2)
792 { 999 {
793 pos_set = 1; 1000 instance.pos = EINA_TRUE;
794 } 1001 }
795 else if (sscanf(geometry,"-%i+%i", &pos_x, &pos_y) == 2) 1002 else if (sscanf(geometry,"-%i+%i", &instance.x, &instance.y) == 2)
796 { 1003 {
797 pos_x = -pos_x; 1004 instance.x = -instance.x;
798 pos_set = 1; 1005 instance.pos = EINA_TRUE;
799 } 1006 }
800 else if (sscanf(geometry,"+%i-%i", &pos_x, &pos_y) == 2) 1007 else if (sscanf(geometry,"+%i-%i", &instance.x, &instance.y) == 2)
801 { 1008 {
802 pos_y = -pos_y; 1009 instance.y = -instance.y;
803 pos_set = 1; 1010 instance.pos = EINA_TRUE;
804 } 1011 }
805 else if (sscanf(geometry,"-%i-%i", &pos_x, &pos_y) == 2) 1012 else if (sscanf(geometry,"-%i-%i", &instance.x, &instance.y) == 2)
806 { 1013 {
807 pos_x = -pos_x; 1014 instance.x = -instance.x;
808 pos_y = -pos_y; 1015 instance.y = -instance.y;
809 pos_set = 1; 1016 instance.pos = EINA_TRUE;
810 } 1017 }
811 } 1018 }
812 1019
813 if (!size_set) 1020 if (!size_set)
814 { 1021 {
815 if (config->custom_geometry) 1022 if (instance.config->custom_geometry)
816 { 1023 {
817 size_w = config->cg_width; 1024 instance.w = instance.config->cg_width;
818 size_h = config->cg_height; 1025 instance.h = instance.config->cg_height;
819 } 1026 }
820 else 1027 else
821 { 1028 {
822 size_w = 80; 1029 instance.w = 80;
823 size_h = 24; 1030 instance.h = 24;
824 } 1031 }
825 } 1032 }
826 1033
827 if (login_shell != 0xff) 1034 elm_theme_overlay_add(NULL,
828 { 1035 config_theme_path_default_get(instance.config));
829 config->login_shell = login_shell; 1036 elm_theme_overlay_add(NULL, config_theme_path_get(instance.config));
830 config->temporary = EINA_TRUE;
831 }
832 login_shell = config->login_shell;
833
834 elm_theme_overlay_add(NULL, config_theme_path_default_get(config));
835 elm_theme_overlay_add(NULL, config_theme_path_get(config));
836 1037
837remote: 1038 if ((!single) && (instance.config->multi_instance))
838 if ((!single) && (config->multi_instance))
839 { 1039 {
840 Ipc_Instance inst;
841 char cwdbuf[4096]; 1040 char cwdbuf[4096];
842 1041
843 memset(&inst, 0, sizeof(Ipc_Instance)); 1042 if (!instance.cd)
844 1043 instance.cd = getcwd(cwdbuf, sizeof(cwdbuf));
845 inst.cmd = cmd; 1044 if (_start_multi(&instance, argv))
846 if (cd) inst.cd = cd;
847 else inst.cd = getcwd(cwdbuf, sizeof(cwdbuf));
848 inst.background = background;
849 inst.name = name;
850 inst.role = role;
851 inst.title = title;
852 inst.icon_name = icon_name;
853 inst.font = font;
854 inst.startup_id = getenv("DESKTOP_STARTUP_ID");
855 inst.x = pos_x;
856 inst.y = pos_y;
857 inst.w = size_w;
858 inst.h = size_h;
859 inst.pos = pos_set;
860 inst.login_shell = login_shell;
861 inst.fullscreen = fullscreen;
862 inst.iconic = iconic;
863 inst.borderless = borderless;
864 inst.override = override;
865 inst.maximized = maximized;
866 inst.hold = hold;
867 inst.nowm = nowm;
868 inst.startup_split = startup_split;
869 if (ipc_instance_add(&inst))
870 goto end; 1045 goto end;
871 } 1046 }
872 if ((!single) && (config->multi_instance)) 1047 else
873 {
874 ipc_instance_new_func_set(main_ipc_new);
875 if (!ipc_serve())
876 {
877 if (remote_try < 1)
878 {
879 remote_try++;
880 goto remote;
881 }
882 }
883 }
884
885 wn = win_new(name, role, title, icon_name, config,
886 fullscreen, iconic, borderless, override, maximized);
887 // set an env so terminal apps can detect they are in terminology :)
888 putenv("TERMINOLOGY=1");
889 unsetenv("DESKTOP_STARTUP_ID");
890
891 config_del(config);
892 config = NULL;
893 if (!wn)
894 {
895 CRITICAL(_("Could not create window."));
896 retval = EXIT_FAILURE;
897 goto end;
898 }
899
900 config = win_config_get(wn);
901
902 term = term_new(wn, config, cmd, login_shell, cd,
903 size_w, size_h, hold, title);
904 if (!term)
905 { 1048 {
906 CRITICAL(_("Could not create terminal widget.")); 1049 _start(&instance);
907 config = NULL;
908 retval = EXIT_FAILURE;
909 goto end;
910 }
911
912 if (win_term_set(wn, term) < 0)
913 {
914 retval = EXIT_FAILURE;
915 goto end;
916 } 1050 }
917
918 main_trans_update(config);
919 main_media_update(config);
920 win_sizing_handle(wn);
921 win = win_evas_object_get(wn);
922 evas_object_show(win);
923 if (startup_split)
924 {
925 unsigned int i = 0;
926 Term *next = term;
927
928 for (i = 0; i < strlen(startup_split); i++)
929 {
930 if (startup_split[i] == 'v')
931 {
932 cmd = cmds_list ? cmds_list->data : NULL;
933 split_vertically(win_evas_object_get(term_win_get(next)),
934 term_termio_get(next), cmd);
935 cmds_list = eina_list_remove_list(cmds_list, cmds_list);
936 }
937 else if (startup_split[i] == 'h')
938 {
939 cmd = cmds_list ? cmds_list->data : NULL;
940 split_horizontally(win_evas_object_get(term_win_get(next)),
941 term_termio_get(next), cmd);
942 cmds_list = eina_list_remove_list(cmds_list, cmds_list);
943 }
944 else if (startup_split[i] == '-')
945 next = term_next_get(next);
946 else
947 {
948 CRITICAL(_("invalid argument found for option -S/--split."
949 " See --help."));
950 goto end;
951 }
952 }
953 if (cmds_list)
954 eina_list_free(cmds_list);
955 }
956 if (pos_set)
957 {
958 int screen_w, screen_h;
959
960 elm_win_screen_size_get(win, NULL, NULL, &screen_w, &screen_h);
961 if (pos_x < 0) pos_x = screen_w + pos_x;
962 if (pos_y < 0) pos_y = screen_h + pos_y;
963 evas_object_move(win, pos_x, pos_y);
964 }
965 if (nowm)
966 ecore_evas_focus_set(ecore_evas_ecore_evas_get(
967 evas_object_evas_get(win)), 1);
968
969 ecore_con_init();
970 ecore_con_url_init();
971
972 controls_init();
973
974 win_scale_wizard(win, term);
975
976 terminology_starting_up = EINA_FALSE;
977
978 elm_run(); 1051 elm_run();
979 1052
980 ecore_con_url_shutdown(); 1053 ecore_con_url_shutdown();
981 ecore_con_shutdown(); 1054 ecore_con_shutdown();
982 1055
983 config = NULL; 1056 instance.config = NULL;
984 end: 1057 end:
985 if (!startup_split) free(cmd); 1058 if (instance.config)
986 if (config)
987 { 1059 {
988 config_del(config); 1060 config_del(instance.config);
989 config = NULL; 1061 instance.config = NULL;
990 } 1062 }
991 1063
992 ipc_shutdown(); 1064 ipc_shutdown();
diff --git a/src/bin/main.h b/src/bin/main.h
index 1a961d4..e870b32 100644
--- a/src/bin/main.h
+++ b/src/bin/main.h
@@ -4,7 +4,7 @@
4#include "config.h" 4#include "config.h"
5 5
6Config * main_config_get(void); 6Config * main_config_get(void);
7void main_new(Evas_Object *win, Evas_Object *term); 7void main_new(Evas_Object *term);
8void main_new_with_dir(Evas_Object *win, Evas_Object *term, const char *wdir); 8void main_new_with_dir(Evas_Object *win, Evas_Object *term, const char *wdir);
9void main_split_h(Evas_Object *win, Evas_Object *term, const char *cmd); 9void main_split_h(Evas_Object *win, Evas_Object *term, const char *cmd);
10void main_split_v(Evas_Object *win, Evas_Object *term, const char *cmd); 10void main_split_v(Evas_Object *win, Evas_Object *term, const char *cmd);
diff --git a/src/bin/media.c b/src/bin/media.c
index b43eadc..6240445 100644
--- a/src/bin/media.c
+++ b/src/bin/media.c
@@ -964,8 +964,8 @@ _smart_del(Evas_Object *obj)
964 if (sd->realf) unlink(sd->realf); 964 if (sd->realf) unlink(sd->realf);
965 close(sd->tmpfd); 965 close(sd->tmpfd);
966 } 966 }
967 if (sd->src) eina_stringshare_del(sd->src); 967 eina_stringshare_del(sd->src);
968 if (sd->realf) eina_stringshare_del(sd->realf); 968 eina_stringshare_del(sd->realf);
969 if (sd->clip) evas_object_del(sd->clip); 969 if (sd->clip) evas_object_del(sd->clip);
970 if (sd->o_img) evas_object_del(sd->o_img); 970 if (sd->o_img) evas_object_del(sd->o_img);
971 if (sd->o_tmp) evas_object_del(sd->o_tmp); 971 if (sd->o_tmp) evas_object_del(sd->o_tmp);
@@ -1248,7 +1248,6 @@ media_add(Evas_Object *parent, const char *src, const Config *config, int mode,
1248 if (!_smart) _smart_init(); 1248 if (!_smart) _smart_init();
1249 obj = evas_object_smart_add(e, _smart); 1249 obj = evas_object_smart_add(e, _smart);
1250 sd = evas_object_smart_data_get(obj); 1250 sd = evas_object_smart_data_get(obj);
1251 if (!sd) return obj;
1252 1251
1253 sd->src = eina_stringshare_add(src); 1252 sd->src = eina_stringshare_add(src);
1254 sd->config = config; 1253 sd->config = config;
diff --git a/src/bin/meson.build b/src/bin/meson.build
index dc6c2a7..6de1d17 100644
--- a/src/bin/meson.build
+++ b/src/bin/meson.build
@@ -31,7 +31,7 @@ terminology_sources = ['private.h',
31 'termptyops.c', 'termptyops.h', 31 'termptyops.c', 'termptyops.h',
32 'termptygfx.c', 'termptygfx.h', 32 'termptygfx.c', 'termptygfx.h',
33 'termptyext.c', 'termptyext.h', 33 'termptyext.c', 'termptyext.h',
34 'termptysave.c', 'termptysave.h', 34 'backlog.c', 'backlog.h',
35 'md5/md5.c', 'md5/md5.h', 35 'md5/md5.c', 'md5/md5.h',
36 'utf8.c', 'utf8.h', 36 'utf8.c', 'utf8.h',
37 'win.c', 'win.h', 37 'win.c', 'win.h',
@@ -49,7 +49,7 @@ tycat_sources = ['tycommon.c', 'tycommon.h', 'tycat.c', 'extns.c', 'extns.h']
49tyls_sources = ['extns.c', 'extns.h', 'tyls.c', 'tycommon.c', 'tycommon.h'] 49tyls_sources = ['extns.c', 'extns.h', 'tyls.c', 'tycommon.c', 'tycommon.h']
50tysend_sources = ['tycommon.c', 'tycommon.h', 'tysend.c'] 50tysend_sources = ['tycommon.c', 'tycommon.h', 'tysend.c']
51tyfuzz_sources = ['termptyesc.c', 'termptyesc.h', 51tyfuzz_sources = ['termptyesc.c', 'termptyesc.h',
52 'termptysave.c', 'termptysave.h', 52 'backlog.c', 'backlog.h',
53 'termptyops.c', 'termptyops.h', 53 'termptyops.c', 'termptyops.h',
54 'termptydbl.c', 'termptydbl.h', 54 'termptydbl.c', 'termptydbl.h',
55 'termptyext.c', 'termptyext.h', 55 'termptyext.c', 'termptyext.h',
@@ -64,7 +64,7 @@ tyfuzz_sources = ['termptyesc.c', 'termptyesc.h',
64 'utils.c', 'utils.h', 64 'utils.c', 'utils.h',
65 'tyfuzz.c'] 65 'tyfuzz.c']
66tytest_sources = ['termptyesc.c', 'termptyesc.h', 66tytest_sources = ['termptyesc.c', 'termptyesc.h',
67 'termptysave.c', 'termptysave.h', 67 'backlog.c', 'backlog.h',
68 'termptyops.c', 'termptyops.h', 68 'termptyops.c', 'termptyops.h',
69 'termptydbl.c', 'termptydbl.h', 69 'termptydbl.c', 'termptydbl.h',
70 'termptyext.c', 'termptyext.h', 70 'termptyext.c', 'termptyext.h',
diff --git a/src/bin/miniview.c b/src/bin/miniview.c
index 6149183..8eb7d55 100644
--- a/src/bin/miniview.c
+++ b/src/bin/miniview.c
@@ -12,6 +12,7 @@
12#include "miniview.h" 12#include "miniview.h"
13#include "utils.h" 13#include "utils.h"
14#include "main.h" 14#include "main.h"
15#include "backlog.h"
15 16
16/* specific log domain to help debug only miniview */ 17/* specific log domain to help debug only miniview */
17int _miniview_log_dom = -1; 18int _miniview_log_dom = -1;
diff --git a/src/bin/options_behavior.c b/src/bin/options_behavior.c
index 1fc4e4a..c945d5d 100644
--- a/src/bin/options_behavior.c
+++ b/src/bin/options_behavior.c
@@ -4,6 +4,8 @@
4#include <math.h> 4#include <math.h>
5#include <Elementary.h> 5#include <Elementary.h>
6#include <assert.h> 6#include <assert.h>
7#include "termpty.h"
8#include "backlog.h"
7#include "config.h" 9#include "config.h"
8#include "termio.h" 10#include "termio.h"
9#include "options.h" 11#include "options.h"
@@ -17,6 +19,8 @@ typedef struct _Behavior_Ctx {
17 Evas_Object *op_wh_current; 19 Evas_Object *op_wh_current;
18 Evas_Object *term; 20 Evas_Object *term;
19 Evas_Object *sld_hide_cursor; 21 Evas_Object *sld_hide_cursor;
22 Evas_Object *backlock_label;
23 char *backlog_msg;
20 Config *config; 24 Config *config;
21} Behavior_Ctx; 25} Behavior_Ctx;
22 26
@@ -86,6 +90,24 @@ sback_units_format(double d)
86} 90}
87 91
88static void 92static void
93_update_backlog_title(Behavior_Ctx *ctx)
94{
95 char *factor = " KMG";
96 double amount = termpty_backlog_memory_get();
97
98 while (amount > 1024.0 && factor[1] != '\0')
99 {
100 amount /= 1024;
101 factor++;
102 }
103 eina_stringshare_del(ctx->backlog_msg);
104 ctx->backlog_msg = (char*) eina_stringshare_printf(
105 _("Scrollback (current memory usage: %'.2f%cB):"),
106 amount, factor[0]);
107 elm_object_text_set(ctx->backlock_label, ctx->backlog_msg);
108}
109
110static void
89_cb_op_behavior_sback_chg(void *data, 111_cb_op_behavior_sback_chg(void *data,
90 Evas_Object *obj, 112 Evas_Object *obj,
91 void *_event EINA_UNUSED) 113 void *_event EINA_UNUSED)
@@ -95,6 +117,7 @@ _cb_op_behavior_sback_chg(void *data,
95 117
96 config->scrollback = (double) sback_double_to_expo_int(elm_slider_value_get(obj)); 118 config->scrollback = (double) sback_double_to_expo_int(elm_slider_value_get(obj));
97 termio_config_update(ctx->term); 119 termio_config_update(ctx->term);
120 _update_backlog_title(ctx);
98 config_save(config); 121 config_save(config);
99} 122}
100 123
@@ -187,6 +210,7 @@ _parent_del_cb(void *data,
187{ 210{
188 Behavior_Ctx *ctx = data; 211 Behavior_Ctx *ctx = data;
189 212
213 eina_stringshare_del(ctx->backlog_msg);
190 free(ctx); 214 free(ctx);
191} 215}
192 216
@@ -563,7 +587,8 @@ options_behavior(Evas_Object *opbox, Evas_Object *term)
563 o = elm_label_add(bx); 587 o = elm_label_add(bx);
564 evas_object_size_hint_weight_set(o, 0.0, 0.0); 588 evas_object_size_hint_weight_set(o, 0.0, 0.0);
565 evas_object_size_hint_align_set(o, 0.0, 0.5); 589 evas_object_size_hint_align_set(o, 0.0, 0.5);
566 elm_object_text_set(o, _("Scrollback:")); 590 ctx->backlock_label = o;
591 _update_backlog_title(ctx);
567 elm_box_pack_end(bx, o); 592 elm_box_pack_end(bx, o);
568 evas_object_show(o); 593 evas_object_show(o);
569 594
diff --git a/src/bin/sb.c b/src/bin/sb.c
index a0dd9e8..f52f9d4 100644
--- a/src/bin/sb.c
+++ b/src/bin/sb.c
@@ -108,8 +108,17 @@ void
108ty_sb_lskip(struct ty_sb *sb, int len) 108ty_sb_lskip(struct ty_sb *sb, int len)
109{ 109{
110 sb->len -= len; 110 sb->len -= len;
111 sb->gap += len; 111 if (sb->len)
112 sb->buf += len; 112 {
113 sb->gap += len;
114 sb->buf += len;
115 }
116 else
117 {
118 /* buffer is empty, get rid of gap */
119 sb->buf -= sb->gap;
120 sb->gap = 0;
121 }
113} 122}
114 123
115void 124void
diff --git a/src/bin/termcmd.c b/src/bin/termcmd.c
index 3b2e733..e038bfc 100644
--- a/src/bin/termcmd.c
+++ b/src/bin/termcmd.c
@@ -57,15 +57,27 @@ _termcmd_font_size(Evas_Object *obj,
57 eina_stringshare_del(config->font.name); 57 eina_stringshare_del(config->font.name);
58 config->font.name = eina_stringshare_add("10x20.pcf"); 58 config->font.name = eina_stringshare_add("10x20.pcf");
59 } 59 }
60 new_size = 20; 60 new_size = config->font.size * 2;
61 } 61 }
62 else if (cmd[0] == '+') // size up 62 else if (cmd[0] == '+') // size up
63 { 63 {
64 new_size = config->font.size + 1; 64 int i;
65
66 new_size = config->font.size;
67 for (i = 0; cmd[i] == '+'; i++)
68 {
69 new_size = ((double)new_size * 1.4) + 1;
70 }
65 } 71 }
66 else if (cmd[0] == '-') // size down 72 else if (cmd[0] == '-') // size down
67 { 73 {
68 new_size = config->font.size - 1; 74 int i;
75
76 new_size = config->font.size;
77 for (i = 0; cmd[i] == '-'; i++)
78 {
79 new_size = (double)(new_size - 1) / 1.4;
80 }
69 } 81 }
70 else 82 else
71 { 83 {
diff --git a/src/bin/termio.c b/src/bin/termio.c
index dea782e..2d86ea7 100644
--- a/src/bin/termio.c
+++ b/src/bin/termio.c
@@ -6,6 +6,7 @@
6#include "termio.h" 6#include "termio.h"
7#include "termiolink.h" 7#include "termiolink.h"
8#include "termpty.h" 8#include "termpty.h"
9#include "backlog.h"
9#include "termptyops.h" 10#include "termptyops.h"
10#include "termcmd.h" 11#include "termcmd.h"
11#include "termptydbl.h" 12#include "termptydbl.h"
@@ -175,11 +176,8 @@ termio_user_title_set(Evas_Object *obj, const char *title)
175 size_t len = 0; 176 size_t len = 0;
176 EINA_SAFETY_ON_NULL_RETURN(sd); 177 EINA_SAFETY_ON_NULL_RETURN(sd);
177 178
178 if (sd->pty->prop.user_title) 179 eina_stringshare_del(sd->pty->prop.user_title);
179 { 180 sd->pty->prop.user_title = NULL;
180 eina_stringshare_del(sd->pty->prop.user_title);
181 sd->pty->prop.user_title = NULL;
182 }
183 181
184 if (title) 182 if (title)
185 { 183 {
@@ -408,7 +406,7 @@ termio_config_update(Evas_Object *obj)
408 406
409 EINA_SAFETY_ON_NULL_RETURN(sd); 407 EINA_SAFETY_ON_NULL_RETURN(sd);
410 408
411 if (sd->font.name) eina_stringshare_del(sd->font.name); 409 eina_stringshare_del(sd->font.name);
412 sd->font.name = NULL; 410 sd->font.name = NULL;
413 411
414 if (sd->config->font.bitmap) 412 if (sd->config->font.bitmap)
@@ -871,11 +869,8 @@ _lost_selection(void *data, Elm_Sel_Type selection)
871 } 869 }
872 if (sd->have_sel) 870 if (sd->have_sel)
873 { 871 {
874 if (sd->sel_str) 872 eina_stringshare_del(sd->sel_str);
875 { 873 sd->sel_str = NULL;
876 eina_stringshare_del(sd->sel_str);
877 sd->sel_str = NULL;
878 }
879 termio_sel_set(sd, EINA_FALSE); 874 termio_sel_set(sd, EINA_FALSE);
880 elm_object_cnp_selection_clear(sd->win, selection); 875 elm_object_cnp_selection_clear(sd->win, selection);
881 termio_smart_update_queue(sd); 876 termio_smart_update_queue(sd);
@@ -905,7 +900,7 @@ termio_take_selection_text(Termio *sd, Elm_Sel_Type type, const char *text)
905 elm_cnp_selection_loss_callback_set(sd->win, type, 900 elm_cnp_selection_loss_callback_set(sd->win, type,
906 _lost_selection, sd->self); 901 _lost_selection, sd->self);
907 sd->have_sel = EINA_TRUE; 902 sd->have_sel = EINA_TRUE;
908 if (sd->sel_str) eina_stringshare_del(sd->sel_str); 903 eina_stringshare_del(sd->sel_str);
909 sd->sel_str = text; 904 sd->sel_str = text;
910} 905}
911 906
@@ -1043,8 +1038,7 @@ _getsel_cb(void *data,
1043 int prev_i = i; 1038 int prev_i = i;
1044 g = eina_unicode_utf8_next_get(s, &i); 1039 g = eina_unicode_utf8_next_get(s, &i);
1045 /* Skip escape codes as a security measure */ 1040 /* Skip escape codes as a security measure */
1046 if ((g < '\n') || 1041 if (! ((g == '\t') || (g == '\n') || (g >= ' ')))
1047 ((g > '\n') && (g < ' ')))
1048 { 1042 {
1049 continue; 1043 continue;
1050 } 1044 }
@@ -1074,9 +1068,9 @@ _getsel_cb(void *data,
1074 const char *fmt = "UNKNOWN"; 1068 const char *fmt = "UNKNOWN";
1075 switch (ev->format) 1069 switch (ev->format)
1076 { 1070 {
1077 case ELM_SEL_FORMAT_TARGETS: fmt = "TARGETS"; break; /* shouldn't happen */ 1071 case ELM_SEL_FORMAT_TARGETS: fmt = "TARGETS"; break;
1078 case ELM_SEL_FORMAT_NONE: fmt = "NONE"; break; 1072 case ELM_SEL_FORMAT_NONE: fmt = "NONE"; break;
1079 case ELM_SEL_FORMAT_TEXT: fmt = "TEXT"; break; 1073 case ELM_SEL_FORMAT_TEXT: fmt = "TEXT"; break; /* shouldn't happen */
1080 case ELM_SEL_FORMAT_MARKUP: fmt = "MARKUP"; break; 1074 case ELM_SEL_FORMAT_MARKUP: fmt = "MARKUP"; break;
1081 case ELM_SEL_FORMAT_IMAGE: fmt = "IMAGE"; break; 1075 case ELM_SEL_FORMAT_IMAGE: fmt = "IMAGE"; break;
1082 case ELM_SEL_FORMAT_VCARD: fmt = "VCARD"; break; 1076 case ELM_SEL_FORMAT_VCARD: fmt = "VCARD"; break;
@@ -1439,11 +1433,9 @@ _remove_links(Termio *sd)
1439{ 1433{
1440 Eina_Bool same_geom = EINA_FALSE; 1434 Eina_Bool same_geom = EINA_FALSE;
1441 1435
1442 if (sd->link.string) 1436 eina_stringshare_del(sd->link.string);
1443 { 1437 sd->link.string = NULL;
1444 eina_stringshare_del(sd->link.string); 1438
1445 sd->link.string = NULL;
1446 }
1447 sd->link.x1 = -1; 1439 sd->link.x1 = -1;
1448 sd->link.y1 = -1; 1440 sd->link.y1 = -1;
1449 sd->link.x2 = -1; 1441 sd->link.x2 = -1;
@@ -2383,8 +2375,7 @@ _smart_mouseover_apply(Termio *sd)
2383 goto end; 2375 goto end;
2384 } 2376 }
2385 2377
2386 if (sd->link.string) 2378 eina_stringshare_del(sd->link.string);
2387 eina_stringshare_del(sd->link.string);
2388 sd->link.string = eina_stringshare_add(s); 2379 sd->link.string = eina_stringshare_add(s);
2389 2380
2390 if ((x1 == sd->link.x1) && (y1 == sd->link.y1) && 2381 if ((x1 == sd->link.x1) && (y1 == sd->link.y1) &&
@@ -2829,13 +2820,13 @@ termio_file_send_ok(const Evas_Object *obj, const char *file)
2829 sd->sendfile.f = fopen(file, "w"); 2820 sd->sendfile.f = fopen(file, "w");
2830 if (sd->sendfile.f) 2821 if (sd->sendfile.f)
2831 { 2822 {
2832 if (sd->sendfile.file) eina_stringshare_del(sd->sendfile.file); 2823 eina_stringshare_del(sd->sendfile.file);
2833 sd->sendfile.file = eina_stringshare_add(file); 2824 sd->sendfile.file = eina_stringshare_add(file);
2834 sd->sendfile.active = EINA_TRUE; 2825 sd->sendfile.active = EINA_TRUE;
2835 termpty_write(ty, "k\n", 2); 2826 termpty_write(ty, "k\n", 2);
2836 return EINA_TRUE; 2827 return EINA_TRUE;
2837 } 2828 }
2838 if (sd->sendfile.file) eina_stringshare_del(sd->sendfile.file); 2829 eina_stringshare_del(sd->sendfile.file);
2839 sd->sendfile.file = NULL; 2830 sd->sendfile.file = NULL;
2840 sd->sendfile.active = EINA_FALSE; 2831 sd->sendfile.active = EINA_FALSE;
2841 termpty_write(ty, "n\n", 2); 2832 termpty_write(ty, "n\n", 2);
@@ -3226,10 +3217,9 @@ _smart_del(Evas_Object *obj)
3226 if (sd->link_do_timer) ecore_timer_del(sd->link_do_timer); 3217 if (sd->link_do_timer) ecore_timer_del(sd->link_do_timer);
3227 if (sd->mouse_move_job) ecore_job_del(sd->mouse_move_job); 3218 if (sd->mouse_move_job) ecore_job_del(sd->mouse_move_job);
3228 if (sd->mouseover_delay) ecore_timer_del(sd->mouseover_delay); 3219 if (sd->mouseover_delay) ecore_timer_del(sd->mouseover_delay);
3229 if (sd->font.name) eina_stringshare_del(sd->font.name); 3220 eina_stringshare_del(sd->font.name);
3230 if (sd->pty) termpty_free(sd->pty); 3221 if (sd->pty) termpty_free(sd->pty);
3231 if (sd->link.string) 3222 eina_stringshare_del(sd->link.string);
3232 eina_stringshare_del(sd->link.string);
3233 if (sd->glayer) evas_object_del(sd->glayer); 3223 if (sd->glayer) evas_object_del(sd->glayer);
3234 if (sd->win) 3224 if (sd->win)
3235 evas_object_event_callback_del_full(sd->win, EVAS_CALLBACK_DEL, 3225 evas_object_event_callback_del_full(sd->win, EVAS_CALLBACK_DEL,
@@ -3255,7 +3245,7 @@ _smart_del(Evas_Object *obj)
3255 } 3245 }
3256 sd->sendfile.active = EINA_FALSE; 3246 sd->sendfile.active = EINA_FALSE;
3257 } 3247 }
3258 if (sd->sel_str) eina_stringshare_del(sd->sel_str); 3248 eina_stringshare_del(sd->sel_str);
3259 if (sd->sel_reset_job) ecore_job_del(sd->sel_reset_job); 3249 if (sd->sel_reset_job) ecore_job_del(sd->sel_reset_job);
3260 EINA_LIST_FREE(sd->cur_chids, chid) eina_stringshare_del(chid); 3250 EINA_LIST_FREE(sd->cur_chids, chid) eina_stringshare_del(chid);
3261 sd->sel_str = NULL; 3251 sd->sel_str = NULL;
@@ -3800,11 +3790,8 @@ _smart_pty_command(void *data)
3800 { 3790 {
3801 sd->sendfile.progress = 0.0; 3791 sd->sendfile.progress = 0.0;
3802 sd->sendfile.size = 0; 3792 sd->sendfile.size = 0;
3803 if (sd->sendfile.file) 3793 eina_stringshare_del(sd->sendfile.file);
3804 { 3794 sd->sendfile.file = NULL;
3805 eina_stringshare_del(sd->sendfile.file);
3806 sd->sendfile.file = NULL;
3807 }
3808 if (sd->sendfile.f) 3795 if (sd->sendfile.f)
3809 { 3796 {
3810 fclose(sd->sendfile.f); 3797 fclose(sd->sendfile.f);
diff --git a/src/bin/termiointernals.c b/src/bin/termiointernals.c
index 555c27a..cd17b29 100644
--- a/src/bin/termiointernals.c
+++ b/src/bin/termiointernals.c
@@ -5,6 +5,7 @@
5#include "termio.h" 5#include "termio.h"
6#include "miniview.h" 6#include "miniview.h"
7#include "termpty.h" 7#include "termpty.h"
8#include "backlog.h"
8#include "termptydbl.h" 9#include "termptydbl.h"
9#include "termptyops.h" 10#include "termptyops.h"
10#include "termiointernals.h" 11#include "termiointernals.h"
@@ -21,6 +22,16 @@ termio_selection_get(Termio *sd,
21{ 22{
22 int x, y; 23 int x, y;
23 24
25#define SB_ADD(STR, LEN) do { \
26 if (ty_sb_add(sb, STR, LEN) < 0) \
27 goto err; \
28} while (0)
29
30#define RTRIM() do { \
31 if (rtrim) \
32 ty_sb_spaces_rtrim(sb); \
33} while (0)
34
24 termpty_backlog_lock(); 35 termpty_backlog_lock();
25 for (y = c1y; y <= c2y; y++) 36 for (y = c1y; y <= c2y; y++)
26 { 37 {
@@ -33,51 +44,91 @@ termio_selection_get(Termio *sd,
33 cells = termpty_cellrow_get(sd->pty, y, &w); 44 cells = termpty_cellrow_get(sd->pty, y, &w);
34 if (!cells || !w) 45 if (!cells || !w)
35 { 46 {
36 if (ty_sb_add(sb, "\n", 1) < 0) goto err; 47 SB_ADD("\n", 1);
37 continue; 48 continue;
38 } 49 }
39 if (w > sd->grid.w) w = sd->grid.w; 50
51 /* Define how much needs to be read on that line */
52 if (w > sd->grid.w)
53 w = sd->grid.w;
40 if (y == c1y && c1x >= w) 54 if (y == c1y && c1x >= w)
41 { 55 {
42 if (rtrim) 56 RTRIM();
43 ty_sb_spaces_rtrim(sb); 57 SB_ADD("\n", 1);
44 if (ty_sb_add(sb, "\n", 1) < 0) goto err;
45 continue; 58 continue;
46 } 59 }
47 start_x = c1x; 60 start_x = c1x;
48 end_x = (c2x >= w) ? w - 1 : c2x; 61 end_x = (c2x >= w) ? w - 1 : c2x;
49 if (c1y != c2y) 62 if (c1y != c2y)
50 { 63 {
51 if (y == c1y) end_x = w - 1; 64 if (y == c1y)
52 else if (y == c2y) start_x = 0; 65 end_x = w - 1;
66 else if (y == c2y)
67 start_x = 0;
53 else 68 else
54 { 69 {
55 start_x = 0; 70 start_x = 0;
56 end_x = w - 1; 71 end_x = w - 1;
57 } 72 }
58 } 73 }
74
59 for (x = start_x; x <= end_x; x++) 75 for (x = start_x; x <= end_x; x++)
60 { 76 {
61 if ((cells[x].codepoint == 0) && (cells[x].att.dblwidth)) 77 if ((cells[x].codepoint == 0) && (cells[x].att.dblwidth))
62 { 78 {
63 if (x < end_x) x++; 79 if (x < end_x)
64 else break; 80 x++;
81 else
82 break;
83 }
84 if (x >= w)
85 break;
86 if (cells[x].att.tab_inserted)
87 {
88 /* There was a tab inserted.
89 * Only output it if there were spaces/empty cells "bellow"
90 */
91 Eina_Bool is_tab = EINA_TRUE;
92 while ((is_tab) && (x < end_x))
93 {
94 if (((cells[x].codepoint == 0) ||
95 (cells[x].att.invisible == 1) ||
96 (cells[x].codepoint == ' ')))
97 {
98 x++;
99 }
100 else
101 {
102 is_tab = EINA_FALSE;
103 }
104 if (cells[x].att.tab_last)
105 {
106 SB_ADD("\t", 1);
107 if (is_tab)
108 {
109 x++;
110 is_tab = EINA_FALSE;
111 }
112 break;
113 }
114 }
65 } 115 }
66 if (x >= w) break;
67 if (cells[x].att.newline) 116 if (cells[x].att.newline)
68 { 117 {
69 last0 = -1; 118 last0 = -1;
70 if ((y != c2y) || (x != end_x)) 119 if ((y != c2y) || (x != end_x))
71 { 120 {
72 if (rtrim) 121 RTRIM();
73 ty_sb_spaces_rtrim(sb); 122 SB_ADD("\n", 1);
74 if (ty_sb_add(sb, "\n", 1) < 0) goto err;
75 } 123 }
76 break; 124 break;
77 } 125 }
78 else if (cells[x].codepoint == 0) 126 else if (cells[x].codepoint == 0)
79 { 127 {
80 if (last0 < 0) last0 = x; 128 /* empty cell, track it to know whether to replace with
129 * spaces */
130 if (last0 < 0)
131 last0 = x;
81 } 132 }
82 else 133 else
83 { 134 {
@@ -90,27 +141,28 @@ termio_selection_get(Termio *sd,
90 last0 = -1; 141 last0 = -1;
91 while (v >= 0) 142 while (v >= 0)
92 { 143 {
93 if (ty_sb_add(sb, " ", 1) < 0) goto err; 144 SB_ADD(" ", 1);
94 v--; 145 v--;
95 } 146 }
96 } 147 }
97 txtlen = codepoint_to_utf8(cells[x].codepoint, txt); 148 txtlen = codepoint_to_utf8(cells[x].codepoint, txt);
98 if (txtlen > 0) 149 if (txtlen > 0)
99 if (ty_sb_add(sb, txt, txtlen) < 0) goto err; 150 SB_ADD(txt, txtlen);
100 if ((x == (w - 1)) && 151 if ((x == (w - 1)) &&
101 ((x != c2x) || (y != c2y))) 152 ((x != c2x) || (y != c2y)))
102 { 153 {
103 if (!cells[x].att.autowrapped) 154 if (!cells[x].att.autowrapped)
104 { 155 {
105 if (rtrim) 156 RTRIM();
106 ty_sb_spaces_rtrim(sb); 157 SB_ADD("\n", 1);
107 if (ty_sb_add(sb, "\n", 1) < 0) goto err;
108 } 158 }
109 } 159 }
110 } 160 }
111 } 161 }
112 if (last0 >= 0) 162 if (last0 >= 0)
113 { 163 {
164 /* line stop by empty cell, need to know whether to insert spaces
165 * or just go to next line */
114 if (y == c2y) 166 if (y == c2y)
115 { 167 {
116 Eina_Bool have_more = EINA_FALSE; 168 Eina_Bool have_more = EINA_FALSE;
@@ -120,8 +172,10 @@ termio_selection_get(Termio *sd,
120 if ((cells[x].codepoint == 0) && 172 if ((cells[x].codepoint == 0) &&
121 (cells[x].att.dblwidth)) 173 (cells[x].att.dblwidth))
122 { 174 {
123 if (x < (w - 1)) x++; 175 if (x < (w - 1))
124 else break; 176 x++;
177 else
178 break;
125 } 179 }
126 if (((cells[x].codepoint != 0) && 180 if (((cells[x].codepoint != 0) &&
127 (cells[x].codepoint != ' ')) || 181 (cells[x].codepoint != ' ')) ||
@@ -133,9 +187,8 @@ termio_selection_get(Termio *sd,
133 } 187 }
134 if (!have_more) 188 if (!have_more)
135 { 189 {
136 if (rtrim) 190 RTRIM();
137 ty_sb_spaces_rtrim(sb); 191 SB_ADD("\n", 1);
138 if (ty_sb_add(sb, "\n", 1) < 0) goto err;
139 } 192 }
140 else 193 else
141 { 194 {
@@ -144,31 +197,34 @@ termio_selection_get(Termio *sd,
144 if ((cells[x].codepoint == 0) && 197 if ((cells[x].codepoint == 0) &&
145 (cells[x].att.dblwidth)) 198 (cells[x].att.dblwidth))
146 { 199 {
147 if (x < (w - 1)) x++; 200 if (x < (w - 1))
148 else break; 201 x++;
202 else
203 break;
149 } 204 }
150 if (x >= w) break; 205 if (x >= w)
151 if (ty_sb_add(sb, " ", 1) < 0) goto err; 206 break;
207 SB_ADD(" ", 1);
152 } 208 }
153 } 209 }
154 } 210 }
155 else 211 else
156 { 212 {
157 if (rtrim) 213 RTRIM();
158 ty_sb_spaces_rtrim(sb); 214 SB_ADD("\n", 1);
159 if (ty_sb_add(sb, "\n", 1) < 0) goto err;
160 } 215 }
161 } 216 }
162 } 217 }
163 termpty_backlog_unlock(); 218 termpty_backlog_unlock();
164 219
165 if (rtrim) 220 RTRIM();
166 ty_sb_spaces_rtrim(sb);
167 221
168 return; 222 return;
169 223
170err: 224err:
171 ty_sb_free(sb); 225 ty_sb_free(sb);
226#undef SB_ADD
227#undef RTRIM
172} 228}
173 229
174 230
@@ -359,9 +415,21 @@ termio_internal_get_selection(Termio *sd, size_t *lenp)
359 415
360 if (isb.len) 416 if (isb.len)
361 { 417 {
418 int res;
362 if (isb.buf[isb.len - 1] != '\n' && i != end_y) 419 if (isb.buf[isb.len - 1] != '\n' && i != end_y)
363 ty_sb_add(&isb, "\n", 1); 420 {
364 ty_sb_add(&sb, isb.buf, isb.len); 421 res = ty_sb_add(&isb, "\n", 1);
422 if (res < 0)
423 {
424 ERR("failure to add newline to selection buffer");
425 }
426 }
427 res = ty_sb_add(&sb, isb.buf, isb.len);
428 if (res < 0)
429 {
430 ERR("failure to add %zd characters to selection buffer",
431 isb.len);
432 }
365 } 433 }
366 ty_sb_free(&isb); 434 ty_sb_free(&isb);
367 } 435 }
@@ -1305,8 +1373,6 @@ _selection_newline_extend_fix(Termio *sd)
1305 termpty_backlog_unlock(); 1373 termpty_backlog_unlock();
1306} 1374}
1307 1375
1308/* }}} */
1309
1310void 1376void
1311termio_selection_dbl_fix(Termio *sd) 1377termio_selection_dbl_fix(Termio *sd)
1312{ 1378{
@@ -1393,6 +1459,7 @@ termio_selection_dbl_fix(Termio *sd)
1393 sd->pty->selection.end.y = end_y; 1459 sd->pty->selection.end.y = end_y;
1394} 1460}
1395 1461
1462/* }}} */
1396 1463
1397static void 1464static void
1398_handle_mouse_down_single_click(Termio *sd, 1465_handle_mouse_down_single_click(Termio *sd,
diff --git a/src/bin/termiolink.c b/src/bin/termiolink.c
index d5a3fd5..8a0696b 100644
--- a/src/bin/termiolink.c
+++ b/src/bin/termiolink.c
@@ -1,5 +1,7 @@
1#include "private.h" 1#include "private.h"
2#include <Elementary.h> 2#include <Elementary.h>
3#include "termpty.h"
4#include "backlog.h"
3#include "termiolink.h" 5#include "termiolink.h"
4#include "termio.h" 6#include "termio.h"
5#include "sb.h" 7#include "sb.h"
diff --git a/src/bin/termpty.c b/src/bin/termpty.c
index 879135f..f1fc815 100644
--- a/src/bin/termpty.c
+++ b/src/bin/termpty.c
@@ -6,7 +6,7 @@
6#include "termpty.h" 6#include "termpty.h"
7#include "termptyesc.h" 7#include "termptyesc.h"
8#include "termptyops.h" 8#include "termptyops.h"
9#include "termptysave.h" 9#include "backlog.h"
10#include "keyin.h" 10#include "keyin.h"
11#if !defined(ENABLE_FUZZING) && !defined(ENABLE_TESTS) 11#if !defined(ENABLE_FUZZING) && !defined(ENABLE_TESTS)
12# include "win.h" 12# include "win.h"
@@ -225,35 +225,13 @@ _pty_size(Termpty *ty)
225} 225}
226 226
227static Eina_Bool 227static Eina_Bool
228_fd_read_do(Termpty *ty, Ecore_Fd_Handler *fd_handler, Eina_Bool false_on_empty) 228_handle_read(Termpty *ty, Eina_Bool false_on_empty)
229{ 229{
230 char buf[4097]; 230 char buf[4097];
231 Eina_Unicode codepoint[4097]; 231 Eina_Unicode codepoint[4097];
232 int len, i, j, reads; 232 int len, i, j, reads;
233 unsigned int k; 233 unsigned int k;
234 234
235 if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_ERROR))
236 {
237 DBG("error while reading from tty slave fd");
238 ty->hand_fd = NULL;
239 return ECORE_CALLBACK_CANCEL;
240 }
241 if (ty->fd == -1)
242 {
243 ty->hand_fd = NULL;
244 return ECORE_CALLBACK_CANCEL;
245 }
246
247/* it seems the BSDs can not read from this side of the pair if the other side
248 * is closed */
249#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__OpenBSD__) || defined(__NetBSD__)
250 if (ty->pid == -1)
251 {
252 ty->hand_fd = NULL;
253 return ECORE_CALLBACK_CANCEL;
254 }
255#endif
256
257 // read up to 64 * 4096 bytes 235 // read up to 64 * 4096 bytes
258 for (reads = 0; reads < 64; reads++) 236 for (reads = 0; reads < 64; reads++)
259 { 237 {
@@ -268,7 +246,7 @@ _fd_read_do(Termpty *ty, Ecore_Fd_Handler *fd_handler, Eina_Bool false_on_empty)
268 } 246 }
269 errno = 0; 247 errno = 0;
270 len = read(ty->fd, rbuf, len); 248 len = read(ty->fd, rbuf, len);
271 if ((len < 0 && errno != EAGAIN) || 249 if ((len < 0 && !(errno == EAGAIN || errno == EINTR)) ||
272 (len == 0 && errno != 0)) 250 (len == 0 && errno != 0))
273 { 251 {
274 /* Do not print error if the child has exited */ 252 /* Do not print error if the child has exited */
@@ -278,7 +256,8 @@ _fd_read_do(Termpty *ty, Ecore_Fd_Handler *fd_handler, Eina_Bool false_on_empty)
278 } 256 }
279 close(ty->fd); 257 close(ty->fd);
280 ty->fd = -1; 258 ty->fd = -1;
281 if (ty->hand_fd) ecore_main_fd_handler_del(ty->hand_fd); 259 if (ty->hand_fd)
260 ecore_main_fd_handler_del(ty->hand_fd);
282 ty->hand_fd = NULL; 261 ty->hand_fd = NULL;
283 return ECORE_CALLBACK_CANCEL; 262 return ECORE_CALLBACK_CANCEL;
284 } 263 }
@@ -337,16 +316,19 @@ _fd_read_do(Termpty *ty, Ecore_Fd_Handler *fd_handler, Eina_Bool false_on_empty)
337// DBG("---------------- handle buf %i", j); 316// DBG("---------------- handle buf %i", j);
338 termpty_handle_buf(ty, codepoint, j); 317 termpty_handle_buf(ty, codepoint, j);
339 } 318 }
340 if (ty->cb.change.func) ty->cb.change.func(ty->cb.change.data); 319 if (ty->cb.change.func)
320 ty->cb.change.func(ty->cb.change.data);
341#if defined(ENABLE_FUZZING) || defined(ENABLE_TESTS) 321#if defined(ENABLE_FUZZING) || defined(ENABLE_TESTS)
342 if (len <= 0) 322 if (len <= 0)
343 { 323 {
344 ty->exit_code = 0; 324 ty->exit_code = 0;
345 ty->pid = -1; 325 ty->pid = -1;
346 326
347 if (ty->hand_exe_exit) ecore_event_handler_del(ty->hand_exe_exit); 327 if (ty->hand_exe_exit)
328 ecore_event_handler_del(ty->hand_exe_exit);
348 ty->hand_exe_exit = NULL; 329 ty->hand_exe_exit = NULL;
349 if (ty->hand_fd) ecore_main_fd_handler_del(ty->hand_fd); 330 if (ty->hand_fd)
331 ecore_main_fd_handler_del(ty->hand_fd);
350 ty->hand_fd = NULL; 332 ty->hand_fd = NULL;
351 ty->fd = -1; 333 ty->fd = -1;
352 ty->slavefd = -1; 334 ty->slavefd = -1;
@@ -355,14 +337,82 @@ _fd_read_do(Termpty *ty, Ecore_Fd_Handler *fd_handler, Eina_Bool false_on_empty)
355 return ECORE_CALLBACK_CANCEL; 337 return ECORE_CALLBACK_CANCEL;
356 } 338 }
357#endif 339#endif
358 if ((false_on_empty) && (len <= 0)) return ECORE_CALLBACK_CANCEL; 340 if ((false_on_empty) && (len <= 0))
359 return EINA_TRUE; 341 return ECORE_CALLBACK_CANCEL;
342
343 return ECORE_CALLBACK_RENEW;
344}
345
346static Eina_Bool
347_handle_write(Termpty *ty)
348{
349 struct ty_sb *sb = &ty->write_buffer;
350 ssize_t len;
351
352 if (!sb->len)
353 return ECORE_CALLBACK_RENEW;
354
355 len = write(ty->fd, sb->buf, sb->len);
356 if (len < 0 && (errno != EINTR && errno != EAGAIN))
357 {
358 ERR(_("Could not write to file descriptor %d: %s"),
359 ty->fd, strerror(errno));
360 return ECORE_CALLBACK_CANCEL;
361 }
362 ty_sb_lskip(sb, len);
363
364 if (!sb->len)
365 ecore_main_fd_handler_active_set(ty->hand_fd,
366 ECORE_FD_ERROR |
367 ECORE_FD_READ);
368
369 return ECORE_CALLBACK_RENEW;
370}
371
372static Eina_Bool
373_fd_do(Termpty *ty, Ecore_Fd_Handler *fd_handler, Eina_Bool false_on_empty)
374{
375 if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_ERROR))
376 {
377 DBG("error while doing I/O on tty slave fd");
378 ty->hand_fd = NULL;
379 return ECORE_CALLBACK_CANCEL;
380 }
381 if (ty->fd == -1)
382 {
383 ty->hand_fd = NULL;
384 return ECORE_CALLBACK_CANCEL;
385 }
386
387/* it seems the BSDs can not read from this side of the pair if the other side
388 * is closed */
389#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__OpenBSD__) || defined(__NetBSD__)
390 if (ty->pid == -1)
391 {
392 ty->hand_fd = NULL;
393 return ECORE_CALLBACK_CANCEL;
394 }
395#endif
396
397 if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_READ))
398 {
399 if (!_handle_read(ty, false_on_empty))
400 return ECORE_CALLBACK_CANCEL;
401 }
402
403 if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_WRITE))
404 {
405 if (!_handle_write(ty))
406 return ECORE_CALLBACK_CANCEL;
407 }
408
409 return ECORE_CALLBACK_PASS_ON;
360} 410}
361 411
362static Eina_Bool 412static Eina_Bool
363_cb_fd_read(void *data, Ecore_Fd_Handler *fd_handler) 413_cb_fd(void *data, Ecore_Fd_Handler *fd_handler)
364{ 414{
365 return _fd_read_do(data, fd_handler, EINA_FALSE); 415 return _fd_do(data, fd_handler, EINA_FALSE);
366} 416}
367 417
368static Eina_Bool 418static Eina_Bool
@@ -386,7 +436,7 @@ _cb_exe_exit(void *data,
386 res = ECORE_CALLBACK_PASS_ON; 436 res = ECORE_CALLBACK_PASS_ON;
387 while (ty->hand_fd && res != ECORE_CALLBACK_CANCEL) 437 while (ty->hand_fd && res != ECORE_CALLBACK_CANCEL)
388 { 438 {
389 res = _fd_read_do(ty, ty->hand_fd, EINA_TRUE); 439 res = _fd_do(ty, ty->hand_fd, EINA_TRUE);
390 } 440 }
391 441
392 if (ty->hand_fd) ecore_main_fd_handler_del(ty->hand_fd); 442 if (ty->hand_fd) ecore_main_fd_handler_del(ty->hand_fd);
@@ -533,7 +583,7 @@ termpty_new(const char *cmd, Eina_Bool login_shell, const char *cd,
533 ty->fd = STDIN_FILENO; 583 ty->fd = STDIN_FILENO;
534 ty->hand_fd = ecore_main_fd_handler_add(ty->fd, 584 ty->hand_fd = ecore_main_fd_handler_add(ty->fd,
535 ECORE_FD_READ | ECORE_FD_ERROR, 585 ECORE_FD_READ | ECORE_FD_ERROR,
536 _cb_fd_read, ty, 586 _cb_fd, ty,
537 NULL, NULL); 587 NULL, NULL);
538 _pty_size(ty); 588 _pty_size(ty);
539 termpty_save_register(ty); 589 termpty_save_register(ty);
@@ -728,6 +778,9 @@ termpty_new(const char *cmd, Eina_Bool login_shell, const char *cd,
728 snprintf(buf, sizeof(buf), "WINDOWID=%lu", window_id); 778 snprintf(buf, sizeof(buf), "WINDOWID=%lu", window_id);
729 putenv(buf); 779 putenv(buf);
730 } 780 }