26 files changed, 7458 insertions, 0 deletions
diff --git a/core/apps/embeddedkonsole/.cvsignore b/core/apps/embeddedkonsole/.cvsignore new file mode 100644 index 0000000..6fe2396 --- a/dev/null +++ b/core/apps/embeddedkonsole/.cvsignore | |||
@@ -0,0 +1,2 @@ | |||
1 | moc_* | ||
2 | Makefile | ||
diff --git a/core/apps/embeddedkonsole/Makefile.in b/core/apps/embeddedkonsole/Makefile.in new file mode 100644 index 0000000..b858cd4 --- a/dev/null +++ b/core/apps/embeddedkonsole/Makefile.in | |||
@@ -0,0 +1,285 @@ | |||
1 | ############################################################################# | ||
2 | |||
3 | ####### Compiler, tools and options | ||
4 | |||
5 | CXX =$(SYSCONF_CXX) $(QT_CXX_MT) | ||
6 | CXXFLAGS=$(SYSCONF_CXXFLAGS_QT) $(SYSCONF_CXXFLAGS) | ||
7 | CC =$(SYSCONF_CC) $(QT_C_MT) | ||
8 | CFLAGS =$(SYSCONF_CFLAGS) | ||
9 | INCPATH =-I$(QPEDIR)/include | ||
10 | LFLAGS =$(SYSCONF_LFLAGS_QT) $(SYSCONF_RPATH_QT) $(SYSCONF_LFLAGS) $(QT_LFLAGS_MT) | ||
11 | LIBS =$(SUBLIBS) -lqpe $(SYSCONF_LIBS_QT) $(SYSCONF_LIBS) $(SYSCONF_LIBS_QTAPP) | ||
12 | MOC =$(SYSCONF_MOC) | ||
13 | UIC =$(SYSCONF_UIC) | ||
14 | |||
15 | ####### Target | ||
16 | |||
17 | DESTDIR = $(QPEDIR)/bin/ | ||
18 | VER_MAJ = 1 | ||
19 | VER_MIN = 0 | ||
20 | VER_PATCH = 0 | ||
21 | TARGET= embeddedkonsole | ||
22 | TARGET1 = lib$(TARGET).so.$(VER_MAJ) | ||
23 | |||
24 | ####### Files | ||
25 | |||
26 | HEADERS =TEWidget.h \ | ||
27 | TEScreen.h \ | ||
28 | TECommon.h \ | ||
29 | TEHistory.h \ | ||
30 | TEmulation.h \ | ||
31 | TEmuVt102.h \ | ||
32 | session.h \ | ||
33 | keytrans.h \ | ||
34 | konsole.h \ | ||
35 | MyPty.h | ||
36 | SOURCES =TEScreen.cpp \ | ||
37 | TEWidget.cpp \ | ||
38 | TEHistory.cpp \ | ||
39 | TEmulation.cpp \ | ||
40 | TEmuVt102.cpp \ | ||
41 | session.cpp \ | ||
42 | keytrans.cpp \ | ||
43 | konsole.cpp \ | ||
44 | main.cpp \ | ||
45 | MyPty.cpp | ||
46 | OBJECTS =TEScreen.o \ | ||
47 | TEWidget.o \ | ||
48 | TEHistory.o \ | ||
49 | TEmulation.o \ | ||
50 | TEmuVt102.o \ | ||
51 | session.o \ | ||
52 | keytrans.o \ | ||
53 | konsole.o \ | ||
54 | main.o \ | ||
55 | MyPty.o | ||
56 | INTERFACES = | ||
57 | UICDECLS = | ||
58 | UICIMPLS = | ||
59 | SRCMOC =moc_TEWidget.cpp \ | ||
60 | moc_TEmulation.cpp \ | ||
61 | moc_TEmuVt102.cpp \ | ||
62 | moc_session.cpp \ | ||
63 | moc_konsole.cpp \ | ||
64 | moc_MyPty.cpp | ||
65 | OBJMOC =moc_TEWidget.o \ | ||
66 | moc_TEmulation.o \ | ||
67 | moc_TEmuVt102.o \ | ||
68 | moc_session.o \ | ||
69 | moc_konsole.o \ | ||
70 | moc_MyPty.o | ||
71 | |||
72 | |||
73 | ####### Implicit rules | ||
74 | |||
75 | .SUFFIXES: .cpp .cxx .cc .C .c | ||
76 | |||
77 | .cpp.o: | ||
78 | $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $< | ||
79 | |||
80 | .cxx.o: | ||
81 | $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $< | ||
82 | |||
83 | .cc.o: | ||
84 | $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $< | ||
85 | |||
86 | .C.o: | ||
87 | $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $< | ||
88 | |||
89 | .c.o: | ||
90 | $(CC) -c $(CFLAGS) $(INCPATH) -o $@ $< | ||
91 | |||
92 | ####### Build rules | ||
93 | |||
94 | |||
95 | all: $(DESTDIR)$(TARGET) | ||
96 | |||
97 | $(DESTDIR)$(TARGET): $(UICDECLS) $(OBJECTS) $(OBJMOC) $(SUBLIBS) | ||
98 | $(SYSCONF_LINK) $(LFLAGS) -o $(DESTDIR)$(TARGET) $(OBJECTS) $(OBJMOC) $(LIBS) | ||
99 | |||
100 | moc: $(SRCMOC) | ||
101 | |||
102 | tmake: | ||
103 | tmake embeddedkonsole.pro | ||
104 | |||
105 | clean: | ||
106 | -rm -f $(OBJECTS) $(OBJMOC) $(SRCMOC) $(UICIMPLS) $(UICDECLS) | ||
107 | -rm -f *~ core | ||
108 | -rm -f allmoc.cpp | ||
109 | |||
110 | ####### Extension Modules | ||
111 | |||
112 | listpromodules: | ||
113 | @echo | ||
114 | |||
115 | listallmodules: | ||
116 | @echo | ||
117 | |||
118 | listaddonpromodules: | ||
119 | @echo | ||
120 | |||
121 | listaddonentmodules: | ||
122 | @echo | ||
123 | |||
124 | |||
125 | REQUIRES=embeddedkonsole | ||
126 | |||
127 | ####### Sub-libraries | ||
128 | |||
129 | |||
130 | ###### Combined headers | ||
131 | |||
132 | |||
133 | |||
134 | ####### Compile | ||
135 | |||
136 | TEScreen.o: TEScreen.cpp \ | ||
137 | TEScreen.h \ | ||
138 | TECommon.h \ | ||
139 | TEHistory.h | ||
140 | |||
141 | TEWidget.o: TEWidget.cpp \ | ||
142 | TEWidget.h \ | ||
143 | TECommon.h \ | ||
144 | session.h \ | ||
145 | MyPty.h \ | ||
146 | TEmuVt102.h \ | ||
147 | TEScreen.h \ | ||
148 | TEHistory.h \ | ||
149 | TEmulation.h \ | ||
150 | keytrans.h | ||
151 | |||
152 | TEHistory.o: TEHistory.cpp \ | ||
153 | TEHistory.h \ | ||
154 | TECommon.h | ||
155 | |||
156 | TEmulation.o: TEmulation.cpp \ | ||
157 | TEmulation.h \ | ||
158 | TEWidget.h \ | ||
159 | TECommon.h \ | ||
160 | TEScreen.h \ | ||
161 | TEHistory.h \ | ||
162 | keytrans.h | ||
163 | |||
164 | TEmuVt102.o: TEmuVt102.cpp \ | ||
165 | TEmuVt102.h \ | ||
166 | TEWidget.h \ | ||
167 | TECommon.h \ | ||
168 | TEScreen.h \ | ||
169 | TEHistory.h \ | ||
170 | TEmulation.h \ | ||
171 | keytrans.h | ||
172 | |||
173 | session.o: session.cpp \ | ||
174 | session.h \ | ||
175 | MyPty.h \ | ||
176 | TEWidget.h \ | ||
177 | TECommon.h \ | ||
178 | TEmuVt102.h \ | ||
179 | TEScreen.h \ | ||
180 | TEHistory.h \ | ||
181 | TEmulation.h \ | ||
182 | keytrans.h | ||
183 | |||
184 | keytrans.o: keytrans.cpp \ | ||
185 | keytrans.h \ | ||
186 | $(QPEDIR)/include/qpe/qpeapplication.h \ | ||
187 | default.keytab.h | ||
188 | |||
189 | konsole.o: konsole.cpp \ | ||
190 | $(QPEDIR)/include/qpe/resource.h \ | ||
191 | $(QPEDIR)/include/qpe/qpetoolbar.h \ | ||
192 | $(QPEDIR)/include/qpe/qpemenubar.h \ | ||
193 | konsole.h \ | ||
194 | MyPty.h \ | ||
195 | TEWidget.h \ | ||
196 | TECommon.h \ | ||
197 | TEmuVt102.h \ | ||
198 | TEScreen.h \ | ||
199 | TEHistory.h \ | ||
200 | TEmulation.h \ | ||
201 | keytrans.h \ | ||
202 | session.h | ||
203 | |||
204 | main.o: main.cpp \ | ||
205 | konsole.h \ | ||
206 | MyPty.h \ | ||
207 | TEWidget.h \ | ||
208 | TECommon.h \ | ||
209 | TEmuVt102.h \ | ||
210 | TEScreen.h \ | ||
211 | TEHistory.h \ | ||
212 | TEmulation.h \ | ||
213 | keytrans.h \ | ||
214 | session.h \ | ||
215 | $(QPEDIR)/include/qpe/qpeapplication.h | ||
216 | |||
217 | MyPty.o: MyPty.cpp \ | ||
218 | MyPty.h | ||
219 | |||
220 | moc_TEWidget.o: moc_TEWidget.cpp \ | ||
221 | TEWidget.h \ | ||
222 | TECommon.h | ||
223 | |||
224 | moc_TEmulation.o: moc_TEmulation.cpp \ | ||
225 | TEmulation.h \ | ||
226 | TEWidget.h \ | ||
227 | TECommon.h \ | ||
228 | TEScreen.h \ | ||
229 | TEHistory.h \ | ||
230 | keytrans.h | ||
231 | |||
232 | moc_TEmuVt102.o: moc_TEmuVt102.cpp \ | ||
233 | TEmuVt102.h \ | ||
234 | TEWidget.h \ | ||
235 | TECommon.h \ | ||
236 | TEScreen.h \ | ||
237 | TEHistory.h \ | ||
238 | TEmulation.h \ | ||
239 | keytrans.h | ||
240 | |||
241 | moc_session.o: moc_session.cpp \ | ||
242 | session.h \ | ||
243 | MyPty.h \ | ||
244 | TEWidget.h \ | ||
245 | TECommon.h \ | ||
246 | TEmuVt102.h \ | ||
247 | TEScreen.h \ | ||
248 | TEHistory.h \ | ||
249 | TEmulation.h \ | ||
250 | keytrans.h | ||
251 | |||
252 | moc_konsole.o: moc_konsole.cpp \ | ||
253 | konsole.h \ | ||
254 | MyPty.h \ | ||
255 | TEWidget.h \ | ||
256 | TECommon.h \ | ||
257 | TEmuVt102.h \ | ||
258 | TEScreen.h \ | ||
259 | TEHistory.h \ | ||
260 | TEmulation.h \ | ||
261 | keytrans.h \ | ||
262 | session.h | ||
263 | |||
264 | moc_MyPty.o: moc_MyPty.cpp \ | ||
265 | MyPty.h | ||
266 | |||
267 | moc_TEWidget.cpp: TEWidget.h | ||
268 | $(MOC) TEWidget.h -o moc_TEWidget.cpp | ||
269 | |||
270 | moc_TEmulation.cpp: TEmulation.h | ||
271 | $(MOC) TEmulation.h -o moc_TEmulation.cpp | ||
272 | |||
273 | moc_TEmuVt102.cpp: TEmuVt102.h | ||
274 | $(MOC) TEmuVt102.h -o moc_TEmuVt102.cpp | ||
275 | |||
276 | moc_session.cpp: session.h | ||
277 | $(MOC) session.h -o moc_session.cpp | ||
278 | |||
279 | moc_konsole.cpp: konsole.h | ||
280 | $(MOC) konsole.h -o moc_konsole.cpp | ||
281 | |||
282 | moc_MyPty.cpp: MyPty.h | ||
283 | $(MOC) MyPty.h -o moc_MyPty.cpp | ||
284 | |||
285 | |||
diff --git a/core/apps/embeddedkonsole/MyPty.cpp b/core/apps/embeddedkonsole/MyPty.cpp new file mode 100644 index 0000000..3622d48 --- a/dev/null +++ b/core/apps/embeddedkonsole/MyPty.cpp | |||
@@ -0,0 +1,279 @@ | |||
1 | /* -------------------------------------------------------------------------- */ | ||
2 | /* */ | ||
3 | /* [MyPty.C] Pseudo Terminal Device */ | ||
4 | /* */ | ||
5 | /* -------------------------------------------------------------------------- */ | ||
6 | /* */ | ||
7 | /* Copyright (c) 1997,1998 by Lars Doelle <lars.doelle@on-line.de> */ | ||
8 | /* */ | ||
9 | /* This file is part of Konsole - an X terminal for KDE */ | ||
10 | /* -------------------------------------------------------------------------- */ | ||
11 | /* */ | ||
12 | /* Ported Konsole to Qt/Embedded */ | ||
13 | /* */ | ||
14 | /* Copyright (C) 2000 by John Ryland <jryland@trolltech.com> */ | ||
15 | /* */ | ||
16 | /* -------------------------------------------------------------------------- */ | ||
17 | |||
18 | /* If you're compiling konsole on non-Linux platforms and find | ||
19 | problems that you can track down to this file, please have | ||
20 | a look into ../README.ports, too. | ||
21 | */ | ||
22 | |||
23 | /*! \file | ||
24 | */ | ||
25 | |||
26 | /*! \class TEPty | ||
27 | |||
28 | \brief Ptys provide a pseudo terminal connection to a program. | ||
29 | |||
30 | Although closely related to pipes, these pseudo terminal connections have | ||
31 | some ability, that makes it nessesary to uses them. Most importent, they | ||
32 | know about changing screen sizes and UNIX job control. | ||
33 | |||
34 | Within the terminal emulation framework, this class represents the | ||
35 | host side of the terminal together with the connecting serial line. | ||
36 | |||
37 | One can create many instances of this class within a program. | ||
38 | As a side effect of using this class, a signal(2) handler is | ||
39 | installed on SIGCHLD. | ||
40 | |||
41 | \par FIXME | ||
42 | |||
43 | [NOTE: much of the technical stuff below will be replaced by forkpty.] | ||
44 | |||
45 | publish the SIGCHLD signal if not related to an instance. | ||
46 | |||
47 | clearify TEPty::done vs. TEPty::~TEPty semantics. | ||
48 | check if pty is restartable via run after done. | ||
49 | |||
50 | \par Pseudo terminals | ||
51 | |||
52 | Pseudo terminals are a unique feature of UNIX, and always come in form of | ||
53 | pairs of devices (/dev/ptyXX and /dev/ttyXX), which are connected to each | ||
54 | other by the operating system. One may think of them as two serial devices | ||
55 | linked by a null-modem cable. Being based on devices the number of | ||
56 | simultanous instances of this class is (globally) limited by the number of | ||
57 | those device pairs, which is 256. | ||
58 | |||
59 | Another technic are UNIX 98 PTY's. These are supported also, and prefered | ||
60 | over the (obsolete) predecessor. | ||
61 | |||
62 | There's a sinister ioctl(2), signal(2) and job control stuff | ||
63 | nessesary to make everything work as it should. | ||
64 | */ | ||
65 | |||
66 | |||
67 | #include <qapplication.h> | ||
68 | #include <qsocketnotifier.h> | ||
69 | #include <qstring.h> | ||
70 | |||
71 | #include <stdlib.h> | ||
72 | #include <stdio.h> | ||
73 | #include <signal.h> | ||
74 | #include <fcntl.h> | ||
75 | #include <unistd.h> | ||
76 | #include <termios.h> | ||
77 | #include <sys/types.h> | ||
78 | #include <sys/ioctl.h> | ||
79 | #include <sys/wait.h> | ||
80 | |||
81 | #ifdef HAVE_OPENPTY | ||
82 | #include <pty.h> | ||
83 | #endif | ||
84 | |||
85 | #include "MyPty.h" | ||
86 | |||
87 | |||
88 | #undef VERBOSE_DEBUG | ||
89 | |||
90 | |||
91 | /* -------------------------------------------------------------------------- */ | ||
92 | |||
93 | /*! | ||
94 | Informs the client program about the | ||
95 | actual size of the window. | ||
96 | */ | ||
97 | |||
98 | void MyPty::setSize(int lines, int columns) | ||
99 | { | ||
100 | struct winsize wsize; | ||
101 | wsize.ws_row = (unsigned short)lines; | ||
102 | wsize.ws_col = (unsigned short)columns; | ||
103 | if(fd < 0) return; | ||
104 | ioctl(fd,TIOCSWINSZ,(char *)&wsize); | ||
105 | } | ||
106 | |||
107 | |||
108 | void MyPty::donePty() | ||
109 | { | ||
110 | // This is code from the Qt DumbTerminal example | ||
111 | int status = 0; | ||
112 | |||
113 | ::close(fd); | ||
114 | |||
115 | if (cpid) { | ||
116 | kill(cpid, SIGHUP); | ||
117 | waitpid(cpid, &status, 0); | ||
118 | } | ||
119 | |||
120 | emit done(status); | ||
121 | } | ||
122 | |||
123 | |||
124 | const char* MyPty::deviceName() | ||
125 | { | ||
126 | return ttynam; | ||
127 | } | ||
128 | |||
129 | |||
130 | void MyPty::error() | ||
131 | { | ||
132 | // This is code from the Qt DumbTerminal example | ||
133 | donePty(); | ||
134 | } | ||
135 | |||
136 | |||
137 | /*! | ||
138 | start the client program. | ||
139 | */ | ||
140 | int MyPty::run(const char* cmd, QStrList &, const char*, int) | ||
141 | { | ||
142 | // This is code from the Qt DumbTerminal example | ||
143 | cpid = fork(); | ||
144 | |||
145 | if ( !cpid ) { | ||
146 | // child - exec shell on tty | ||
147 | for (int sig = 1; sig < NSIG; sig++) signal(sig,SIG_DFL); | ||
148 | int ttyfd = open(ttynam, O_RDWR); | ||
149 | dup2(ttyfd, STDIN_FILENO); | ||
150 | dup2(ttyfd, STDOUT_FILENO); | ||
151 | dup2(ttyfd, STDERR_FILENO); | ||
152 | // should be done with tty, so close it | ||
153 | close(ttyfd); | ||
154 | static struct termios ttmode; | ||
155 | if ( setsid() < 0 ) | ||
156 | perror( "failed to set process group" ); | ||
157 | #if defined (TIOCSCTTY) | ||
158 | // grabbed from APUE by Stevens | ||
159 | ioctl(STDIN_FILENO, TIOCSCTTY, 0); | ||
160 | #endif | ||
161 | tcgetattr( STDIN_FILENO, &ttmode ); | ||
162 | ttmode.c_cc[VINTR] = 3; | ||
163 | ttmode.c_cc[VERASE] = 8; | ||
164 | tcsetattr( STDIN_FILENO, TCSANOW, &ttmode ); | ||
165 | setenv("TERM","vt100",1); | ||
166 | setenv("COLORTERM","0",1); | ||
167 | |||
168 | if (getuid() == 0) { | ||
169 | char msg[] = "WARNING: You are running this shell as root!\n"; | ||
170 | write(ttyfd, msg, sizeof(msg)); | ||
171 | } | ||
172 | execl(cmd, cmd, 0); | ||
173 | |||
174 | donePty(); | ||
175 | exit(-1); | ||
176 | } | ||
177 | |||
178 | // parent - continue as a widget | ||
179 | QSocketNotifier* sn_r = new QSocketNotifier(fd,QSocketNotifier::Read,this); | ||
180 | QSocketNotifier* sn_e = new QSocketNotifier(fd,QSocketNotifier::Exception,this); | ||
181 | connect(sn_r,SIGNAL(activated(int)),this,SLOT(readPty())); | ||
182 | connect(sn_e,SIGNAL(activated(int)),this,SLOT(error())); | ||
183 | |||
184 | return 0; | ||
185 | } | ||
186 | |||
187 | int MyPty::openPty() | ||
188 | { | ||
189 | // This is code from the Qt DumbTerminal example | ||
190 | int ptyfd = -1; | ||
191 | |||
192 | #ifdef HAVE_OPENPTY | ||
193 | int ttyfd; | ||
194 | if ( openpty(&ptyfd,&ttyfd,ttynam,0,0) ) | ||
195 | ptyfd = -1; | ||
196 | else | ||
197 | close(ttyfd); // we open the ttynam ourselves. | ||
198 | #else | ||
199 | for (const char* c0 = "pqrstuvwxyzabcde"; ptyfd < 0 && *c0 != 0; c0++) { | ||
200 | for (const char* c1 = "0123456789abcdef"; ptyfd < 0 && *c1 != 0; c1++) { | ||
201 | sprintf(ptynam,"/dev/pty%c%c",*c0,*c1); | ||
202 | sprintf(ttynam,"/dev/tty%c%c",*c0,*c1); | ||
203 | if ((ptyfd = ::open(ptynam,O_RDWR)) >= 0) { | ||
204 | if (geteuid() != 0 && !access(ttynam,R_OK|W_OK) == 0) { | ||
205 | ::close(ptyfd); | ||
206 | ptyfd = -1; | ||
207 | } | ||
208 | } | ||
209 | } | ||
210 | } | ||
211 | #endif | ||
212 | |||
213 | if ( ptyfd < 0 ) { | ||
214 | qApp->exit(1); | ||
215 | return -1; | ||
216 | } | ||
217 | |||
218 | return ptyfd; | ||
219 | } | ||
220 | |||
221 | /*! | ||
222 | Create an instance. | ||
223 | */ | ||
224 | MyPty::MyPty() : cpid(0) | ||
225 | { | ||
226 | fd = openPty(); | ||
227 | } | ||
228 | |||
229 | /*! | ||
230 | Destructor. | ||
231 | Note that the related client program is not killed | ||
232 | (yet) when a instance is deleted. | ||
233 | */ | ||
234 | MyPty::~MyPty() | ||
235 | { | ||
236 | donePty(); | ||
237 | } | ||
238 | |||
239 | |||
240 | /*! sends len bytes through the line */ | ||
241 | void MyPty::send_bytes(const char* s, int len) | ||
242 | { | ||
243 | |||
244 | #ifdef VERBOSE_DEBUG | ||
245 | // verbose debug | ||
246 | printf("sending bytes:\n"); | ||
247 | for (int i = 0; i < len; i++) | ||
248 | printf("%c", s[i]); | ||
249 | printf("\n"); | ||
250 | #endif | ||
251 | |||
252 | ::write(fd, s, len); | ||
253 | } | ||
254 | |||
255 | /*! indicates that a block of data is received */ | ||
256 | void MyPty::readPty() | ||
257 | { | ||
258 | char buf[4096]; | ||
259 | |||
260 | int len = ::read( fd, buf, 4096 ); | ||
261 | |||
262 | if (len == -1) | ||
263 | donePty(); | ||
264 | |||
265 | if (len < 0) | ||
266 | return; | ||
267 | |||
268 | emit block_in(buf,len); | ||
269 | |||
270 | #ifdef VERBOSE_DEBUG | ||
271 | // verbose debug | ||
272 | printf("read bytes:\n"); | ||
273 | for (int i = 0; i < len; i++) | ||
274 | printf("%c", buf[i]); | ||
275 | printf("\n"); | ||
276 | #endif | ||
277 | |||
278 | } | ||
279 | |||
diff --git a/core/apps/embeddedkonsole/MyPty.h b/core/apps/embeddedkonsole/MyPty.h new file mode 100644 index 0000000..b2a5b58 --- a/dev/null +++ b/core/apps/embeddedkonsole/MyPty.h | |||
@@ -0,0 +1,88 @@ | |||
1 | /* -------------------------------------------------------------------------- */ | ||
2 | /* */ | ||
3 | /* [MyPty.h] Pseudo Terminal Device */ | ||
4 | /* */ | ||
5 | /* -------------------------------------------------------------------------- */ | ||
6 | /* */ | ||
7 | /* Copyright (c) 1997,1998 by Lars Doelle <lars.doelle@on-line.de> */ | ||
8 | /* */ | ||
9 | /* This file is part of Konsole - an X terminal for KDE */ | ||
10 | /* */ | ||
11 | /* -------------------------------------------------------------------------- */ | ||
12 | /* */ | ||
13 | /* Ported Konsole to Qt/Embedded */ | ||
14 | /* */ | ||
15 | /* Copyright (C) 2000 by John Ryland <jryland@trolltech.com> */ | ||
16 | /* */ | ||
17 | /* -------------------------------------------------------------------------- */ | ||
18 | |||
19 | /*! \file | ||
20 | */ | ||
21 | |||
22 | #ifndef MY_PTY_H | ||
23 | #define MY_PTY_H | ||
24 | |||
25 | #include <qobject.h> | ||
26 | #include <qstrlist.h> | ||
27 | |||
28 | |||
29 | class MyPty : public QObject | ||
30 | { | ||
31 | Q_OBJECT | ||
32 | |||
33 | public: | ||
34 | |||
35 | MyPty(); | ||
36 | ~MyPty(); | ||
37 | |||
38 | /*! | ||
39 | having a `run' separate from the constructor allows to make | ||
40 | the necessary connections to the signals and slots of the | ||
41 | instance before starting the execution of the client. | ||
42 | */ | ||
43 | int run(const char* pgm, QStrList & args, const char* term, int addutmp); | ||
44 | |||
45 | public slots: | ||
46 | |||
47 | void send_bytes(const char* s, int len); | ||
48 | void setSize(int lines, int columns); | ||
49 | void error(); | ||
50 | |||
51 | signals: | ||
52 | |||
53 | /*! | ||
54 | emitted when the client program terminates. | ||
55 | \param status the wait(2) status code of the terminated client program. | ||
56 | */ | ||
57 | void done(int status); | ||
58 | |||
59 | /*! | ||
60 | emitted when a new block of data comes in. | ||
61 | \param s - the data | ||
62 | \param len - the length of the block | ||
63 | */ | ||
64 | void block_in(const char* s, int len); | ||
65 | |||
66 | public: | ||
67 | |||
68 | void send_byte(char s); | ||
69 | // void send_string(const char* s); | ||
70 | |||
71 | const char* deviceName(); | ||
72 | |||
73 | protected slots: | ||
74 | void readPty(); | ||
75 | void donePty(); | ||
76 | |||
77 | private: | ||
78 | int openPty(); | ||
79 | |||
80 | private: | ||
81 | |||
82 | char ptynam[16]; // "/dev/ptyxx" | "/dev/ptmx" | ||
83 | char ttynam[16]; // "/dev/ttyxx" | "/dev/pts/########..." | ||
84 | int fd; | ||
85 | int cpid; | ||
86 | }; | ||
87 | |||
88 | #endif | ||
diff --git a/core/apps/embeddedkonsole/TECommon.h b/core/apps/embeddedkonsole/TECommon.h new file mode 100644 index 0000000..261d51b --- a/dev/null +++ b/core/apps/embeddedkonsole/TECommon.h | |||
@@ -0,0 +1,114 @@ | |||
1 | /* -------------------------------------------------------------------------- */ | ||
2 | /* */ | ||
3 | /* [TECommon.h] Common Definitions */ | ||
4 | /* */ | ||
5 | /* -------------------------------------------------------------------------- */ | ||
6 | /* */ | ||
7 | /* Copyright (c) 1997,1998 by Lars Doelle <lars.doelle@on-line.de> */ | ||
8 | /* */ | ||
9 | /* This file is part of Konsole - an X terminal for KDE */ | ||
10 | /* */ | ||
11 | /* -------------------------------------------------------------------------- */ | ||
12 | /* */ | ||
13 | /* Ported Konsole to Qt/Embedded */ | ||
14 | /* */ | ||
15 | /* Copyright (C) 2000 by John Ryland <jryland@trolltech.com> */ | ||
16 | /* */ | ||
17 | /* -------------------------------------------------------------------------- */ | ||
18 | |||
19 | /*! \file TECommon.h | ||
20 | \brief Definitions shared between TEScreen and TEWidget. | ||
21 | */ | ||
22 | |||
23 | #ifndef TECOMMON_H | ||
24 | #define TECOMMON_H | ||
25 | |||
26 | #include <qcolor.h> | ||
27 | |||
28 | #ifndef BOOL | ||
29 | typedef int BOOL; | ||
30 | #endif | ||
31 | |||
32 | #ifndef FALSE | ||
33 | #define FALSE 0 | ||
34 | #endif | ||
35 | |||
36 | #ifndef TRUE | ||
37 | #define TRUE 1 | ||
38 | #endif | ||
39 | |||
40 | #ifndef UINT8 | ||
41 | typedef unsigned char UINT8; | ||
42 | #endif | ||
43 | |||
44 | #ifndef UINT16 | ||
45 | typedef unsigned short UINT16; | ||
46 | #endif | ||
47 | |||
48 | // Attributed Character Representations /////////////////////////////// | ||
49 | |||
50 | // Colors | ||
51 | |||
52 | #define BASE_COLORS (2+8) | ||
53 | #define INTENSITIES 2 | ||
54 | #define TABLE_COLORS (INTENSITIES*BASE_COLORS) | ||
55 | |||
56 | #define DEFAULT_FORE_COLOR 0 | ||
57 | #define DEFAULT_BACK_COLOR 1 | ||
58 | |||
59 | #define DEFAULT_RENDITION 0 | ||
60 | #define RE_BOLD (1 << 0) | ||
61 | #define RE_BLINK (1 << 1) | ||
62 | #define RE_UNDERLINE (1 << 2) | ||
63 | #define RE_REVERSE (1 << 3) // Screen only | ||
64 | #define RE_INTENSIVE (1 << 3) // Widget only | ||
65 | |||
66 | /*! \class ca | ||
67 | * \brief a character with rendition attributes. | ||
68 | */ | ||
69 | |||
70 | class ca | ||
71 | { | ||
72 | public: | ||
73 | inline ca(UINT16 _c = ' ', | ||
74 | UINT8 _f = DEFAULT_FORE_COLOR, | ||
75 | UINT8 _b = DEFAULT_BACK_COLOR, | ||
76 | UINT8 _r = DEFAULT_RENDITION) | ||
77 | : c(_c), f(_f), b(_b), r(_r) {} | ||
78 | public: | ||
79 | UINT16 c; // character | ||
80 | UINT8 f; // foreground color | ||
81 | UINT8 b; // background color | ||
82 | UINT8 r; // rendition | ||
83 | public: | ||
84 | friend BOOL operator == (ca a, ca b); | ||
85 | friend BOOL operator != (ca a, ca b); | ||
86 | }; | ||
87 | |||
88 | inline BOOL operator == (ca a, ca b) | ||
89 | { | ||
90 | return a.c == b.c && a.f == b.f && a.b == b.b && a.r == b.r; | ||
91 | } | ||
92 | |||
93 | inline BOOL operator != (ca a, ca b) | ||
94 | { | ||
95 | return a.c != b.c || a.f != b.f || a.b != b.b || a.r != b.r; | ||
96 | } | ||
97 | |||
98 | /*! | ||
99 | */ | ||
100 | struct ColorEntry | ||
101 | { | ||
102 | ColorEntry(QColor c, bool tr, bool b) : color(c), transparent(tr), bold(b) {} | ||
103 | ColorEntry() : transparent(false), bold(false) {} // default constructors | ||
104 | void operator=(const ColorEntry& rhs) { | ||
105 | color = rhs.color; | ||
106 | transparent = rhs.transparent; | ||
107 | bold = rhs.bold; | ||
108 | } | ||
109 | QColor color; | ||
110 | bool transparent; // if used on bg | ||
111 | bool bold; // if used on fg | ||
112 | }; | ||
113 | |||
114 | #endif // TECOMMON_H | ||
diff --git a/core/apps/embeddedkonsole/TEHistory.cpp b/core/apps/embeddedkonsole/TEHistory.cpp new file mode 100644 index 0000000..317ce57 --- a/dev/null +++ b/core/apps/embeddedkonsole/TEHistory.cpp | |||
@@ -0,0 +1,212 @@ | |||
1 | /* -------------------------------------------------------------------------- */ | ||
2 | /* */ | ||
3 | /* [TEHistory.C] History Buffer */ | ||
4 | /* */ | ||
5 | /* -------------------------------------------------------------------------- */ | ||
6 | /* */ | ||
7 | /* Copyright (c) 1997,1998 by Lars Doelle <lars.doelle@on-line.de> */ | ||
8 | /* */ | ||
9 | /* This file is part of Konsole - an X terminal for KDE */ | ||
10 | /* */ | ||
11 | /* -------------------------------------------------------------------------- */ | ||
12 | /* */ | ||
13 | /* Ported Konsole to Qt/Embedded */ | ||
14 | /* */ | ||
15 | /* Copyright (C) 2000 by John Ryland <jryland@trolltech.com> */ | ||
16 | /* */ | ||
17 | /* -------------------------------------------------------------------------- */ | ||
18 | |||
19 | #include "TEHistory.h" | ||
20 | #include <stdlib.h> | ||
21 | #include <assert.h> | ||
22 | #include <stdio.h> | ||
23 | #include <sys/types.h> | ||
24 | #include <unistd.h> | ||
25 | #include <errno.h> | ||
26 | |||
27 | #define HERE printf("%s(%d): here\n",__FILE__,__LINE__) | ||
28 | |||
29 | /* | ||
30 | An arbitrary long scroll. | ||
31 | |||
32 | One can modify the scroll only by adding either cells | ||
33 | or newlines, but access it randomly. | ||
34 | |||
35 | The model is that of an arbitrary wide typewriter scroll | ||
36 | in that the scroll is a serie of lines and each line is | ||
37 | a serie of cells with no overwriting permitted. | ||
38 | |||
39 | The implementation provides arbitrary length and numbers | ||
40 | of cells and line/column indexed read access to the scroll | ||
41 | at constant costs. | ||
42 | |||
43 | FIXME: some complain about the history buffer comsuming the | ||
44 | memory of their machines. This problem is critical | ||
45 | since the history does not behave gracefully in cases | ||
46 | where the memory is used up completely. | ||
47 | |||
48 | I put in a workaround that should handle it problem | ||
49 | now gracefully. I'm not satisfied with the solution. | ||
50 | |||
51 | FIXME: Terminating the history is not properly indicated | ||
52 | in the menu. We should throw a signal. | ||
53 | |||
54 | FIXME: There is noticable decrease in speed, also. Perhaps, | ||
55 | there whole feature needs to be revisited therefore. | ||
56 | Disadvantage of a more elaborated, say block-oriented | ||
57 | scheme with wrap around would be it's complexity. | ||
58 | */ | ||
59 | |||
60 | //FIXME: tempory replacement for tmpfile | ||
61 | // this is here one for debugging purpose. | ||
62 | |||
63 | //#define tmpfile xTmpFile | ||
64 | |||
65 | FILE* xTmpFile() | ||
66 | { | ||
67 | static int fid = 0; | ||
68 | char fname[80]; | ||
69 | sprintf(fname,"TmpFile.%d",fid++); | ||
70 | return fopen(fname,"w"); | ||
71 | } | ||
72 | |||
73 | |||
74 | // History Buffer /////////////////////////////////////////// | ||
75 | |||
76 | /* | ||
77 | A Row(X) data type which allows adding elements to the end. | ||
78 | */ | ||
79 | |||
80 | HistoryBuffer::HistoryBuffer() | ||
81 | { | ||
82 | ion = -1; | ||
83 | length = 0; | ||
84 | } | ||
85 | |||
86 | HistoryBuffer::~HistoryBuffer() | ||
87 | { | ||
88 | setScroll(FALSE); | ||
89 | } | ||
90 | |||
91 | void HistoryBuffer::setScroll(bool on) | ||
92 | { | ||
93 | if (on == hasScroll()) return; | ||
94 | |||
95 | if (on) | ||
96 | { | ||
97 | assert( ion < 0 ); | ||
98 | assert( length == 0); | ||
99 | FILE* tmp = tmpfile(); if (!tmp) { perror("konsole: cannot open temp file.\n"); return; } | ||
100 | ion = dup(fileno(tmp)); if (ion<0) perror("konsole: cannot dup temp file.\n"); | ||
101 | fclose(tmp); | ||
102 | } | ||
103 | else | ||
104 | { | ||
105 | assert( ion >= 0 ); | ||
106 | close(ion); | ||
107 | ion = -1; | ||
108 | length = 0; | ||
109 | } | ||
110 | } | ||
111 | |||
112 | bool HistoryBuffer::hasScroll() | ||
113 | { | ||
114 | return ion >= 0; | ||
115 | } | ||
116 | |||
117 | void HistoryBuffer::add(const unsigned char* bytes, int len) | ||
118 | { int rc; | ||
119 | assert(hasScroll()); | ||
120 | rc = lseek(ion,length,SEEK_SET); if (rc < 0) { perror("HistoryBuffer::add.seek"); setScroll(FALSE); return; } | ||
121 | rc = write(ion,bytes,len); if (rc < 0) { perror("HistoryBuffer::add.write"); setScroll(FALSE); return; } | ||
122 | length += rc; | ||
123 | } | ||
124 | |||
125 | void HistoryBuffer::get(unsigned char* bytes, int len, int loc) | ||
126 | { int rc; | ||
127 | assert(hasScroll()); | ||
128 | if (loc < 0 || len < 0 || loc + len > length) | ||
129 | fprintf(stderr,"getHist(...,%d,%d): invalid args.\n",len,loc); | ||
130 | rc = lseek(ion,loc,SEEK_SET); if (rc < 0) { perror("HistoryBuffer::get.seek"); setScroll(FALSE); return; } | ||
131 | rc = read(ion,bytes,len); if (rc < 0) { perror("HistoryBuffer::get.read"); setScroll(FALSE); return; } | ||
132 | } | ||
133 | |||
134 | int HistoryBuffer::len() | ||
135 | { | ||
136 | return length; | ||
137 | } | ||
138 | |||
139 | // History Scroll ////////////////////////////////////// | ||
140 | |||
141 | /* | ||
142 | The history scroll makes a Row(Row(Cell)) from | ||
143 | two history buffers. The index buffer contains | ||
144 | start of line positions which refere to the cells | ||
145 | buffer. | ||
146 | |||
147 | Note that index[0] addresses the second line | ||
148 | (line #1), while the first line (line #0) starts | ||
149 | at 0 in cells. | ||
150 | */ | ||
151 | |||
152 | HistoryScroll::HistoryScroll() | ||
153 | { | ||
154 | } | ||
155 | |||
156 | HistoryScroll::~HistoryScroll() | ||
157 | { | ||
158 | } | ||
159 | |||
160 | void HistoryScroll::setScroll(bool on) | ||
161 | { | ||
162 | index.setScroll(on); | ||
163 | cells.setScroll(on); | ||
164 | } | ||
165 | |||
166 | bool HistoryScroll::hasScroll() | ||
167 | { | ||
168 | return index.hasScroll() && cells.hasScroll(); | ||
169 | } | ||
170 | |||
171 | int HistoryScroll::getLines() | ||
172 | { | ||
173 | if (!hasScroll()) return 0; | ||
174 | return index.len() / sizeof(int); | ||
175 | } | ||
176 | |||
177 | int HistoryScroll::getLineLen(int lineno) | ||
178 | { | ||
179 | if (!hasScroll()) return 0; | ||
180 | return (startOfLine(lineno+1) - startOfLine(lineno)) / sizeof(ca); | ||
181 | } | ||
182 | |||
183 | int HistoryScroll::startOfLine(int lineno) | ||
184 | { | ||
185 | if (lineno <= 0) return 0; | ||
186 | if (!hasScroll()) return 0; | ||
187 | if (lineno <= getLines()) | ||
188 | { int res; | ||
189 | index.get((unsigned char*)&res,sizeof(int),(lineno-1)*sizeof(int)); | ||
190 | return res; | ||
191 | } | ||
192 | return cells.len(); | ||
193 | } | ||
194 | |||
195 | void HistoryScroll::getCells(int lineno, int colno, int count, ca res[]) | ||
196 | { | ||
197 | assert(hasScroll()); | ||
198 | cells.get((unsigned char*)res,count*sizeof(ca),startOfLine(lineno)+colno*sizeof(ca)); | ||
199 | } | ||
200 | |||
201 | void HistoryScroll::addCells(ca text[], int count) | ||
202 | { | ||
203 | if (!hasScroll()) return; | ||
204 | cells.add((unsigned char*)text,count*sizeof(ca)); | ||
205 | } | ||
206 | |||
207 | void HistoryScroll::addLine() | ||
208 | { | ||
209 | if (!hasScroll()) return; | ||
210 | int locn = cells.len(); | ||
211 | index.add((unsigned char*)&locn,sizeof(int)); | ||
212 | } | ||
diff --git a/core/apps/embeddedkonsole/TEHistory.h b/core/apps/embeddedkonsole/TEHistory.h new file mode 100644 index 0000000..8339ec6 --- a/dev/null +++ b/core/apps/embeddedkonsole/TEHistory.h | |||
@@ -0,0 +1,75 @@ | |||
1 | /* -------------------------------------------------------------------------- */ | ||
2 | /* */ | ||
3 | /* [TEHistory.H] History Buffer */ | ||
4 | /* */ | ||
5 | /* -------------------------------------------------------------------------- */ | ||
6 | /* */ | ||
7 | /* Copyright (c) 1997,1998 by Lars Doelle <lars.doelle@on-line.de> */ | ||
8 | /* */ | ||
9 | /* This file is part of Konsole - an X terminal for KDE */ | ||
10 | /* */ | ||
11 | /* -------------------------------------------------------------------------- */ | ||
12 | /* */ | ||
13 | /* Ported Konsole to Qt/Embedded */ | ||
14 | /* */ | ||
15 | /* Copyright (C) 2000 by John Ryland <jryland@trolltech.com> */ | ||
16 | /* */ | ||
17 | /* -------------------------------------------------------------------------- */ | ||
18 | |||
19 | #ifndef TEHISTORY_H | ||
20 | #define TEHISTORY_H | ||
21 | |||
22 | #include "TECommon.h" | ||
23 | |||
24 | /* | ||
25 | An extendable tmpfile(1) based buffer. | ||
26 | */ | ||
27 | class HistoryBuffer | ||
28 | { | ||
29 | public: | ||
30 | HistoryBuffer(); | ||
31 | ~HistoryBuffer(); | ||
32 | |||
33 | public: | ||
34 | void setScroll(bool on); | ||
35 | bool hasScroll(); | ||
36 | |||
37 | public: | ||
38 | void add(const unsigned char* bytes, int len); | ||
39 | void get(unsigned char* bytes, int len, int loc); | ||
40 | int len(); | ||
41 | |||
42 | private: | ||
43 | int ion; | ||
44 | int length; | ||
45 | }; | ||
46 | |||
47 | class HistoryScroll | ||
48 | { | ||
49 | public: | ||
50 | HistoryScroll(); | ||
51 | ~HistoryScroll(); | ||
52 | |||
53 | public: | ||
54 | void setScroll(bool on); | ||
55 | bool hasScroll(); | ||
56 | |||
57 | public: // access to history | ||
58 | int getLines(); | ||
59 | int getLineLen(int lineno); | ||
60 | void getCells(int lineno, int colno, int count, ca res[]); | ||
61 | |||
62 | public: // backward compatibility (obsolete) | ||
63 | ca getCell(int lineno, int colno) { ca res; getCells(lineno,colno,1,&res); return res; } | ||
64 | |||
65 | public: // adding lines. | ||
66 | void addCells(ca a[], int count); | ||
67 | void addLine(); | ||
68 | |||
69 | private: | ||
70 | int startOfLine(int lineno); | ||
71 | HistoryBuffer index; // lines Row(int) | ||
72 | HistoryBuffer cells; // text Row(ca) | ||
73 | }; | ||
74 | |||
75 | #endif // TEHISTORY_H | ||
diff --git a/core/apps/embeddedkonsole/TEScreen.cpp b/core/apps/embeddedkonsole/TEScreen.cpp new file mode 100644 index 0000000..a3d115d --- a/dev/null +++ b/core/apps/embeddedkonsole/TEScreen.cpp | |||
@@ -0,0 +1,1197 @@ | |||
1 | /* -------------------------------------------------------------------------- */ | ||
2 | /* */ | ||
3 | /* [TEScreen.C] Screen Data Type */ | ||
4 | /* */ | ||
5 | /* -------------------------------------------------------------------------- */ | ||
6 | /* */ | ||
7 | /* Copyright (c) 1997,1998 by Lars Doelle <lars.doelle@on-line.de> */ | ||
8 | /* */ | ||
9 | /* This file is part of Konsole - an X terminal for KDE */ | ||
10 | /* */ | ||
11 | /* -------------------------------------------------------------------------- */ | ||
12 | /* */ | ||
13 | /* Ported Konsole to Qt/Embedded */ | ||
14 | /* */ | ||
15 | /* Copyright (C) 2000 by John Ryland <jryland@trolltech.com> */ | ||
16 | /* */ | ||
17 | /* -------------------------------------------------------------------------- */ | ||
18 | |||
19 | /*! \file | ||
20 | */ | ||
21 | |||
22 | /*! \class TEScreen | ||
23 | |||
24 | \brief The image manipulated by the emulation. | ||
25 | |||
26 | This class implements the operations of the terminal emulation framework. | ||
27 | It is a complete passive device, driven by the emulation decoder | ||
28 | (TEmuVT102). By this it forms in fact an ADT, that defines operations | ||
29 | on a rectangular image. | ||
30 | |||
31 | It does neither know how to display its image nor about escape sequences. | ||
32 | It is further independent of the underlying toolkit. By this, one can even | ||
33 | use this module for an ordinary text surface. | ||
34 | |||
35 | Since the operations are called by a specific emulation decoder, one may | ||
36 | collect their different operations here. | ||
37 | |||
38 | The state manipulated by the operations is mainly kept in `image', though | ||
39 | it is a little more complex bejond this. See the header file of the class. | ||
40 | |||
41 | \sa TEWidget \sa VT102Emulation | ||
42 | */ | ||
43 | |||
44 | #include <stdio.h> | ||
45 | #include <stdlib.h> | ||
46 | #include <unistd.h> | ||
47 | // #include <kdebug.h> | ||
48 | |||
49 | #include <assert.h> | ||
50 | #include <string.h> | ||
51 | #include <ctype.h> | ||
52 | |||
53 | #include "TEScreen.h" | ||
54 | |||
55 | #define HERE printf("%s(%d): here\n",__FILE__,__LINE__) | ||
56 | |||
57 | //FIXME: this is emulation specific. Use FALSE for xterm, TRUE for ANSI. | ||
58 | //FIXME: see if we can get this from terminfo. | ||
59 | #define BS_CLEARS FALSE | ||
60 | |||
61 | #define loc(X,Y) ((Y)*columns+(X)) | ||
62 | |||
63 | /*! creates a `TEScreen' of `lines' lines and `columns' columns. | ||
64 | */ | ||
65 | |||
66 | TEScreen::TEScreen(int lines, int columns) | ||
67 | { | ||
68 | this->lines = lines; | ||
69 | this->columns = columns; | ||
70 | |||
71 | image = (ca*) malloc(lines*columns*sizeof(ca)); | ||
72 | tabstops = NULL; initTabStops(); | ||
73 | |||
74 | histCursor = 0; | ||
75 | |||
76 | clearSelection(); | ||
77 | reset(); | ||
78 | } | ||
79 | |||
80 | /*! Destructor | ||
81 | */ | ||
82 | |||
83 | TEScreen::~TEScreen() | ||
84 | { | ||
85 | free(image); | ||
86 | if (tabstops) free(tabstops); | ||
87 | } | ||
88 | |||
89 | /* ------------------------------------------------------------------------- */ | ||
90 | /* */ | ||
91 | /* Normalized Screen Operations */ | ||
92 | /* */ | ||
93 | /* ------------------------------------------------------------------------- */ | ||
94 | |||
95 | // Cursor Setting -------------------------------------------------------------- | ||
96 | |||
97 | /*! \section Cursor | ||
98 | |||
99 | The `cursor' is a location within the screen that is implicitely used in | ||
100 | many operations. The operations within this section allow to manipulate | ||
101 | the cursor explicitly and to obtain it's value. | ||
102 | |||
103 | The position of the cursor is guarantied to be between (including) 0 and | ||
104 | `columns-1' and `lines-1'. | ||
105 | */ | ||
106 | |||
107 | /*! | ||
108 | Move the cursor up. | ||
109 | |||
110 | The cursor will not be moved beyond the top margin. | ||
111 | */ | ||
112 | |||
113 | void TEScreen::cursorUp(int n) | ||
114 | //=CUU | ||
115 | { | ||
116 | if (n == 0) n = 1; // Default | ||
117 | int stop = cuY < tmargin ? 0 : tmargin; | ||
118 | cuX = QMIN(columns-1,cuX); // nowrap! | ||
119 | cuY = QMAX(stop,cuY-n); | ||
120 | } | ||
121 | |||
122 | /*! | ||
123 | Move the cursor down. | ||
124 | |||
125 | The cursor will not be moved beyond the bottom margin. | ||
126 | */ | ||
127 | |||
128 | void TEScreen::cursorDown(int n) | ||
129 | //=CUD | ||
130 | { | ||
131 | if (n == 0) n = 1; // Default | ||
132 | int stop = cuY > bmargin ? lines-1 : bmargin; | ||
133 | cuX = QMIN(columns-1,cuX); // nowrap! | ||
134 | cuY = QMIN(stop,cuY+n); | ||
135 | } | ||
136 | |||
137 | /*! | ||
138 | Move the cursor left. | ||
139 | |||
140 | The cursor will not move beyond the first column. | ||
141 | */ | ||
142 | |||
143 | void TEScreen::cursorLeft(int n) | ||
144 | //=CUB | ||
145 | { | ||
146 | if (n == 0) n = 1; // Default | ||
147 | cuX = QMIN(columns-1,cuX); // nowrap! | ||
148 | cuX = QMAX(0,cuX-n); | ||
149 | } | ||
150 | |||
151 | /*! | ||
152 | Move the cursor left. | ||
153 | |||
154 | The cursor will not move beyond the rightmost column. | ||
155 | */ | ||
156 | |||
157 | void TEScreen::cursorRight(int n) | ||
158 | //=CUF | ||
159 | { | ||
160 | if (n == 0) n = 1; // Default | ||
161 | cuX = QMIN(columns-1,cuX+n); | ||
162 | } | ||
163 | |||
164 | /*! | ||
165 | Set top and bottom margin. | ||
166 | */ | ||
167 | |||
168 | void TEScreen::setMargins(int top, int bot) | ||
169 | //=STBM | ||
170 | { | ||
171 | if (top == 0) top = 1; // Default | ||
172 | if (bot == 0) bot = lines; // Default | ||
173 | top = top - 1; // Adjust to internal lineno | ||
174 | bot = bot - 1; // Adjust to internal lineno | ||
175 | if ( !( 0 <= top && top < bot && bot < lines ) ) | ||
176 | { fprintf(stderr,"%s(%d) : setRegion(%d,%d) : bad range.\n", | ||
177 | __FILE__,__LINE__,top,bot); | ||
178 | return; // Default error action: ignore | ||
179 | } | ||
180 | tmargin = top; | ||
181 | bmargin = bot; | ||
182 | cuX = 0; | ||
183 | cuY = getMode(MODE_Origin) ? top : 0; | ||
184 | } | ||
185 | |||
186 | /*! | ||
187 | Move the cursor down one line. | ||
188 | |||
189 | If cursor is on bottom margin, the region between the | ||
190 | actual top and bottom margin is scrolled up instead. | ||
191 | */ | ||
192 | |||
193 | void TEScreen::index() | ||
194 | //=IND | ||
195 | { | ||
196 | if (cuY == bmargin) | ||
197 | { | ||
198 | if (tmargin == 0 && bmargin == lines-1) addHistLine(); // hist.history | ||
199 | scrollUp(tmargin,1); | ||
200 | } | ||
201 | else if (cuY < lines-1) | ||
202 | cuY += 1; | ||
203 | } | ||
204 | |||
205 | /*! | ||
206 | Move the cursor up one line. | ||
207 | |||
208 | If cursor is on the top margin, the region between the | ||
209 | actual top and bottom margin is scrolled down instead. | ||
210 | */ | ||
211 | |||
212 | void TEScreen::reverseIndex() | ||
213 | //=RI | ||
214 | { | ||
215 | if (cuY == tmargin) | ||
216 | scrollDown(tmargin,1); | ||
217 | else if (cuY > 0) | ||
218 | cuY -= 1; | ||
219 | } | ||
220 | |||
221 | /*! | ||
222 | Move the cursor to the begin of the next line. | ||
223 | |||
224 | If cursor is on bottom margin, the region between the | ||
225 | actual top and bottom margin is scrolled up. | ||
226 | */ | ||
227 | |||
228 | void TEScreen::NextLine() | ||
229 | //=NEL | ||
230 | { | ||
231 | Return(); index(); | ||
232 | } | ||
233 | |||
234 | // Line Editing ---------------------------------------------------------------- | ||
235 | |||
236 | /*! \section inserting / deleting characters | ||
237 | */ | ||
238 | |||
239 | /*! erase `n' characters starting from (including) the cursor position. | ||
240 | |||
241 | The line is filled in from the right with spaces. | ||
242 | */ | ||
243 | |||
244 | void TEScreen::eraseChars(int n) | ||
245 | { | ||
246 | if (n == 0) n = 1; // Default | ||
247 | int p = QMAX(0,QMIN(cuX+n-1,columns-1)); | ||
248 | clearImage(loc(cuX,cuY),loc(p,cuY),' '); | ||
249 | } | ||
250 | |||
251 | /*! delete `n' characters starting from (including) the cursor position. | ||
252 | |||
253 | The line is filled in from the right with spaces. | ||
254 | */ | ||
255 | |||
256 | void TEScreen::deleteChars(int n) | ||
257 | { | ||
258 | if (n == 0) n = 1; // Default | ||
259 | int p = QMAX(0,QMIN(cuX+n,columns-1)); | ||
260 | moveImage(loc(cuX,cuY),loc(p,cuY),loc(columns-1,cuY)); | ||
261 | clearImage(loc(columns-n,cuY),loc(columns-1,cuY),' '); | ||
262 | } | ||
263 | |||
264 | /*! insert `n' spaces at the cursor position. | ||
265 | |||
266 | The cursor is not moved by the operation. | ||
267 | */ | ||
268 | |||
269 | void TEScreen::insertChars(int n) | ||
270 | { | ||
271 | if (n == 0) n = 1; // Default | ||
272 | int p = QMAX(0,QMIN(columns-1-n,columns-1)); | ||
273 | int q = QMAX(0,QMIN(cuX+n,columns-1)); | ||
274 | moveImage(loc(q,cuY),loc(cuX,cuY),loc(p,cuY)); | ||
275 | clearImage(loc(cuX,cuY),loc(q-1,cuY),' '); | ||
276 | } | ||
277 | |||
278 | /*! delete `n' lines starting from (including) the cursor position. | ||
279 | |||
280 | The cursor is not moved by the operation. | ||
281 | */ | ||
282 | |||
283 | void TEScreen::deleteLines(int n) | ||
284 | { | ||
285 | if (n == 0) n = 1; // Default | ||
286 | scrollUp(cuY,n); | ||
287 | } | ||
288 | |||
289 | /*! insert `n' lines at the cursor position. | ||
290 | |||
291 | The cursor is not moved by the operation. | ||
292 | */ | ||
293 | |||
294 | void TEScreen::insertLines(int n) | ||
295 | { | ||
296 | if (n == 0) n = 1; // Default | ||
297 | scrollDown(cuY,n); | ||
298 | } | ||
299 | |||
300 | // Mode Operations ----------------------------------------------------------- | ||
301 | |||
302 | /*! Set a specific mode. */ | ||
303 | |||
304 | void TEScreen::setMode(int m) | ||
305 | { | ||
306 | currParm.mode[m] = TRUE; | ||
307 | switch(m) | ||
308 | { | ||
309 | case MODE_Origin : cuX = 0; cuY = tmargin; break; //FIXME: home | ||
310 | } | ||
311 | } | ||
312 | |||
313 | /*! Reset a specific mode. */ | ||
314 | |||
315 | void TEScreen::resetMode(int m) | ||
316 | { | ||
317 | currParm.mode[m] = FALSE; | ||
318 | switch(m) | ||
319 | { | ||
320 | case MODE_Origin : cuX = 0; cuY = 0; break; //FIXME: home | ||
321 | } | ||
322 | } | ||
323 | |||
324 | /*! Save a specific mode. */ | ||
325 | |||
326 | void TEScreen::saveMode(int m) | ||
327 | { | ||
328 | saveParm.mode[m] = currParm.mode[m]; | ||
329 | } | ||
330 | |||
331 | /*! Restore a specific mode. */ | ||
332 | |||
333 | void TEScreen::restoreMode(int m) | ||
334 | { | ||
335 | currParm.mode[m] = saveParm.mode[m]; | ||
336 | } | ||
337 | |||
338 | //NOTE: this is a helper function | ||
339 | /*! Return the setting a specific mode. */ | ||
340 | BOOL TEScreen::getMode(int m) | ||
341 | { | ||
342 | return currParm.mode[m]; | ||
343 | } | ||
344 | |||
345 | /*! Save the cursor position and the rendition attribute settings. */ | ||
346 | |||
347 | void TEScreen::saveCursor() | ||
348 | { | ||
349 | sa_cuX = cuX; | ||
350 | sa_cuY = cuY; | ||
351 | sa_cu_re = cu_re; | ||
352 | sa_cu_fg = cu_fg; | ||
353 | sa_cu_bg = cu_bg; | ||
354 | } | ||
355 | |||
356 | /*! Restore the cursor position and the rendition attribute settings. */ | ||
357 | |||
358 | void TEScreen::restoreCursor() | ||
359 | { | ||
360 | cuX = QMIN(sa_cuX,columns-1); | ||
361 | cuY = QMIN(sa_cuY,lines-1); | ||
362 | cu_re = sa_cu_re; | ||
363 | cu_fg = sa_cu_fg; | ||
364 | cu_bg = sa_cu_bg; | ||
365 | effectiveRendition(); | ||
366 | } | ||
367 | |||
368 | /* ------------------------------------------------------------------------- */ | ||
369 | /* */ | ||
370 | /* Screen Operations */ | ||
371 | /* */ | ||
372 | /* ------------------------------------------------------------------------- */ | ||
373 | |||
374 | /*! Assing a new size to the screen. | ||
375 | |||
376 | The topmost left position is maintained, while lower lines | ||
377 | or right hand side columns might be removed or filled with | ||
378 | spaces to fit the new size. | ||
379 | |||
380 | The region setting is reset to the whole screen and the | ||
381 | tab positions reinitialized. | ||
382 | */ | ||
383 | |||
384 | void TEScreen::resizeImage(int new_lines, int new_columns) | ||
385 | { | ||
386 | |||
387 | if (cuY > new_lines-1) | ||
388 | { // attempt to preserve focus and lines | ||
389 | bmargin = lines-1; //FIXME: margin lost | ||
390 | for (int i = 0; i < cuY-(new_lines-1); i++) | ||
391 | { | ||
392 | addHistLine(); scrollUp(0,1); | ||
393 | } | ||
394 | } | ||
395 | |||
396 | // make new image | ||
397 | ca* newimg = (ca*)malloc(new_lines*new_columns*sizeof(ca)); | ||
398 | |||
399 | clearSelection(); | ||
400 | |||
401 | // clear new image | ||
402 | for (int y = 0; y < new_lines; y++) | ||
403 | for (int x = 0; x < new_columns; x++) | ||
404 | { | ||
405 | newimg[y*new_columns+x].c = ' '; | ||
406 | newimg[y*new_columns+x].f = DEFAULT_FORE_COLOR; | ||
407 | newimg[y*new_columns+x].b = DEFAULT_BACK_COLOR; | ||
408 | newimg[y*new_columns+x].r = DEFAULT_RENDITION; | ||
409 | } | ||
410 | int cpy_lines = QMIN(new_lines, lines); | ||
411 | int cpy_columns = QMIN(new_columns,columns); | ||
412 | // copy to new image | ||
413 | for (int y = 0; y < cpy_lines; y++) | ||
414 | for (int x = 0; x < cpy_columns; x++) | ||
415 | { | ||
416 | newimg[y*new_columns+x].c = image[loc(x,y)].c; | ||
417 | newimg[y*new_columns+x].f = image[loc(x,y)].f; | ||
418 | newimg[y*new_columns+x].b = image[loc(x,y)].b; | ||
419 | newimg[y*new_columns+x].r = image[loc(x,y)].r; | ||
420 | } | ||
421 | free(image); | ||
422 | image = newimg; | ||
423 | lines = new_lines; | ||
424 | columns = new_columns; | ||
425 | cuX = QMIN(cuX,columns-1); | ||
426 | cuY = QMIN(cuY,lines-1); | ||
427 | |||
428 | // FIXME: try to keep values, evtl. | ||
429 | tmargin=0; | ||
430 | bmargin=lines-1; | ||
431 | initTabStops(); | ||
432 | clearSelection(); | ||
433 | } | ||
434 | |||
435 | /* | ||
436 | Clarifying rendition here and in TEWidget. | ||
437 | |||
438 | currently, TEWidget's color table is | ||
439 | 0 1 2 .. 9 10 .. 17 | ||
440 | dft_fg, dft_bg, dim 0..7, intensive 0..7 | ||
441 | |||
442 | cu_fg, cu_bg contain values 0..8; | ||
443 | - 0 = default color | ||
444 | - 1..8 = ansi specified color | ||
445 | |||
446 | re_fg, re_bg contain values 0..17 | ||
447 | due to the TEWidget's color table | ||
448 | |||
449 | rendition attributes are | ||
450 | |||
451 | attr widget screen | ||
452 | -------------- ------ ------ | ||
453 | RE_UNDERLINE XX XX affects foreground only | ||
454 | RE_BLINK XX XX affects foreground only | ||
455 | RE_BOLD XX XX affects foreground only | ||
456 | RE_REVERSE -- XX | ||
457 | RE_TRANSPARENT XX -- affects background only | ||
458 | RE_INTENSIVE XX -- affects foreground only | ||
459 | |||
460 | Note that RE_BOLD is used in both widget | ||
461 | and screen rendition. Since xterm/vt102 | ||
462 | is to poor to distinguish between bold | ||
463 | (which is a font attribute) and intensive | ||
464 | (which is a color attribute), we translate | ||
465 | this and RE_BOLD in falls eventually appart | ||
466 | into RE_BOLD and RE_INTENSIVE. | ||
467 | */ | ||
468 | |||
469 | void TEScreen::reverseRendition(ca* p) | ||
470 | { UINT8 f = p->f; UINT8 b = p->b; | ||
471 | p->f = b; p->b = f; //p->r &= ~RE_TRANSPARENT; | ||
472 | } | ||
473 | |||
474 | void TEScreen::effectiveRendition() | ||
475 | // calculate rendition | ||
476 | { | ||
477 | ef_re = cu_re & (RE_UNDERLINE | RE_BLINK); | ||
478 | if (cu_re & RE_REVERSE) | ||
479 | { | ||
480 | ef_fg = cu_bg; | ||
481 | ef_bg = cu_fg; | ||
482 | } | ||
483 | else | ||
484 | { | ||
485 | ef_fg = cu_fg; | ||
486 | ef_bg = cu_bg; | ||
487 | } | ||
488 | if (cu_re & RE_BOLD) | ||
489 | { | ||
490 | if (ef_fg < BASE_COLORS) | ||
491 | ef_fg += BASE_COLORS; | ||
492 | else | ||
493 | ef_fg -= BASE_COLORS; | ||
494 | } | ||
495 | } | ||
496 | |||
497 | /*! | ||
498 | returns the image. | ||
499 | |||
500 | Get the size of the image by \sa getLines and \sa getColumns. | ||
501 | |||
502 | NOTE that the image returned by this function must later be | ||
503 | freed. | ||
504 | |||
505 | */ | ||
506 | |||
507 | ca* TEScreen::getCookedImage() | ||
508 | { int x,y; | ||
509 | ca* merged = (ca*)malloc(lines*columns*sizeof(ca)); | ||
510 | ca dft(' ',DEFAULT_FORE_COLOR,DEFAULT_BACK_COLOR,DEFAULT_RENDITION); | ||
511 | |||
512 | for (y = 0; (y < lines) && (y < (hist.getLines()-histCursor)); y++) | ||
513 | { | ||
514 | int len = QMIN(columns,hist.getLineLen(y+histCursor)); | ||
515 | int yp = y*columns; | ||
516 | int yq = (y+histCursor)*columns; | ||
517 | |||
518 | hist.getCells(y+histCursor,0,len,merged+yp); | ||
519 | for (x = len; x < columns; x++) merged[yp+x] = dft; | ||
520 | for (x = 0; x < columns; x++) | ||
521 | { int p=x + yp; int q=x + yq; | ||
522 | if ( ( q >= sel_TL ) && ( q <= sel_BR ) ) | ||
523 | reverseRendition(&merged[p]); // for selection | ||
524 | } | ||
525 | } | ||
526 | if (lines >= hist.getLines()-histCursor) | ||
527 | { | ||
528 | for (y = (hist.getLines()-histCursor); y < lines ; y++) | ||
529 | { | ||
530 | int yp = y*columns; | ||
531 | int yq = (y+histCursor)*columns; | ||
532 | int yr = (y-hist.getLines()+histCursor)*columns; | ||
533 | for (x = 0; x < columns; x++) | ||
534 | { int p = x + yp; int q = x + yq; int r = x + yr; | ||
535 | merged[p] = image[r]; | ||
536 | if ( q >= sel_TL && q <= sel_BR ) | ||
537 | reverseRendition(&merged[p]); // for selection | ||
538 | } | ||
539 | |||
540 | } | ||
541 | } | ||
542 | // evtl. inverse display | ||
543 | if (getMode(MODE_Screen)) | ||
544 | { int i,n = lines*columns; | ||
545 | for (i = 0; i < n; i++) | ||
546 | reverseRendition(&merged[i]); // for reverse display | ||
547 | } | ||
548 | if (getMode(MODE_Cursor) && (cuY+(hist.getLines()-histCursor) < lines)) // cursor visible | ||
549 | reverseRendition(&merged[loc(cuX,cuY+(hist.getLines()-histCursor))]); | ||
550 | return merged; | ||
551 | } | ||
552 | |||
553 | |||
554 | /*! | ||
555 | */ | ||
556 | |||
557 | void TEScreen::reset() | ||
558 | { | ||
559 | setMode(MODE_Wrap ); saveMode(MODE_Wrap ); // wrap at end of margin | ||
560 | resetMode(MODE_Origin); saveMode(MODE_Origin); // position refere to [1,1] | ||
561 | resetMode(MODE_Insert); saveMode(MODE_Insert); // overstroke | ||
562 | setMode(MODE_Cursor); // cursor visible | ||
563 | resetMode(MODE_Screen); // screen not inverse | ||
564 | resetMode(MODE_NewLine); | ||
565 | |||
566 | tmargin=0; | ||
567 | bmargin=lines-1; | ||
568 | |||
569 | setDefaultRendition(); | ||
570 | saveCursor(); | ||
571 | |||
572 | clear(); | ||
573 | } | ||
574 | |||
575 | /*! Clear the entire screen and home the cursor. | ||
576 | */ | ||
577 | |||
578 | void TEScreen::clear() | ||
579 | { | ||
580 | clearEntireScreen(); | ||
581 | home(); | ||
582 | } | ||
583 | |||
584 | /*! Moves the cursor left one column. | ||
585 | */ | ||
586 | |||
587 | void TEScreen::BackSpace() | ||
588 | { | ||
589 | cuX = QMAX(0,cuX-1); | ||
590 | if (BS_CLEARS) image[loc(cuX,cuY)].c = ' '; | ||
591 | } | ||
592 | |||
593 | /*! | ||
594 | */ | ||
595 | |||
596 | void TEScreen::Tabulate() | ||
597 | { | ||
598 | // note that TAB is a format effector (does not write ' '); | ||
599 | cursorRight(1); while(cuX < columns-1 && !tabstops[cuX]) cursorRight(1); | ||
600 | } | ||
601 | |||
602 | void TEScreen::clearTabStops() | ||
603 | { | ||
604 | for (int i = 0; i < columns; i++) tabstops[i-1] = FALSE; | ||
605 | } | ||
606 | |||
607 | void TEScreen::changeTabStop(bool set) | ||
608 | { | ||
609 | if (cuX >= columns) return; | ||
610 | tabstops[cuX] = set; | ||
611 | } | ||
612 | |||
613 | void TEScreen::initTabStops() | ||
614 | { | ||
615 | if (tabstops) free(tabstops); | ||
616 | tabstops = (bool*)malloc(columns*sizeof(bool)); | ||
617 | // Arrg! The 1st tabstop has to be one longer than the other. | ||
618 | // i.e. the kids start counting from 0 instead of 1. | ||
619 | // Other programs might behave correctly. Be aware. | ||
620 | for (int i = 0; i < columns; i++) tabstops[i] = (i%8 == 0 && i != 0); | ||
621 | } | ||
622 | |||
623 | /*! | ||
624 | This behaves either as IND (Screen::Index) or as NEL (Screen::NextLine) | ||
625 | depending on the NewLine Mode (LNM). This mode also | ||
626 | affects the key sequence returned for newline ([CR]LF). | ||
627 | */ | ||
628 | |||
629 | void TEScreen::NewLine() | ||
630 | { | ||
631 | if (getMode(MODE_NewLine)) Return(); | ||
632 | index(); | ||
633 | } | ||
634 | |||
635 | /*! put `c' literally onto the screen at the current cursor position. | ||
636 | |||
637 | VT100 uses the convention to produce an automatic newline (am) | ||
638 | with the *first* character that would fall onto the next line (xenl). | ||
639 | */ | ||
640 | |||
641 | void TEScreen::checkSelection(int from, int to) | ||
642 | { | ||
643 | if (sel_begin == -1) return; | ||
644 | int scr_TL = loc(0, hist.getLines()); | ||
645 | //Clear entire selection if it overlaps region [from, to] | ||
646 | if ( (sel_BR > (from+scr_TL) )&&(sel_TL < (to+scr_TL)) ) | ||
647 | { | ||
648 | clearSelection(); | ||
649 | } | ||
650 | } | ||
651 | |||
652 | void TEScreen::ShowCharacter(unsigned short c) | ||
653 | { | ||
654 | // Note that VT100 does wrapping BEFORE putting the character. | ||
655 | // This has impact on the assumption of valid cursor positions. | ||
656 | // We indicate the fact that a newline has to be triggered by | ||
657 | // putting the cursor one right to the last column of the screen. | ||
658 | |||
659 | if (cuX >= columns) | ||
660 | { | ||
661 | if (getMode(MODE_Wrap)) NextLine(); else cuX = columns-1; | ||
662 | } | ||
663 | |||
664 | if (getMode(MODE_Insert)) insertChars(1); | ||
665 | |||
666 | int i = loc(cuX,cuY); | ||
667 | |||
668 | checkSelection(i, i); // check if selection is still valid. | ||
669 | |||
670 | image[i].c = c; | ||
671 | image[i].f = ef_fg; | ||
672 | image[i].b = ef_bg; | ||
673 | image[i].r = ef_re; | ||
674 | |||
675 | cuX += 1; | ||
676 | } | ||
677 | |||
678 | // Region commands ------------------------------------------------------------- | ||
679 | |||
680 | |||
681 | /*! scroll up `n' lines within current region. | ||
682 | The `n' new lines are cleared. | ||
683 | \sa setRegion \sa scrollDown | ||
684 | */ | ||
685 | |||
686 | void TEScreen::scrollUp(int from, int n) | ||
687 | { | ||
688 | if (n <= 0 || from + n > bmargin) return; | ||
689 | //FIXME: make sure `tmargin', `bmargin', `from', `n' is in bounds. | ||
690 | moveImage(loc(0,from),loc(0,from+n),loc(columns-1,bmargin)); | ||
691 | clearImage(loc(0,bmargin-n+1),loc(columns-1,bmargin),' '); | ||
692 | } | ||
693 | |||
694 | /*! scroll down `n' lines within current region. | ||
695 | The `n' new lines are cleared. | ||
696 | \sa setRegion \sa scrollUp | ||
697 | */ | ||
698 | |||
699 | void TEScreen::scrollDown(int from, int n) | ||
700 | { | ||
701 | //FIXME: make sure `tmargin', `bmargin', `from', `n' is in bounds. | ||
702 | if (n <= 0) return; | ||
703 | if (from > bmargin) return; | ||
704 | if (from + n > bmargin) n = bmargin - from; | ||
705 | moveImage(loc(0,from+n),loc(0,from),loc(columns-1,bmargin-n)); | ||
706 | clearImage(loc(0,from),loc(columns-1,from+n-1),' '); | ||
707 | } | ||
708 | |||
709 | /*! position the cursor to a specific line and column. */ | ||
710 | void TEScreen::setCursorYX(int y, int x) | ||
711 | { | ||
712 | setCursorY(y); setCursorX(x); | ||
713 | } | ||
714 | |||
715 | /*! Set the cursor to x-th line. */ | ||
716 | |||
717 | void TEScreen::setCursorX(int x) | ||
718 | { | ||
719 | if (x == 0) x = 1; // Default | ||
720 | x -= 1; // Adjust | ||
721 | cuX = QMAX(0,QMIN(columns-1, x)); | ||
722 | } | ||
723 | |||
724 | /*! Set the cursor to y-th line. */ | ||
725 | |||
726 | void TEScreen::setCursorY(int y) | ||
727 | { | ||
728 | if (y == 0) y = 1; // Default | ||
729 | y -= 1; // Adjust | ||
730 | cuY = QMAX(0,QMIN(lines -1, y + (getMode(MODE_Origin) ? tmargin : 0) )); | ||
731 | } | ||
732 | |||
733 | /*! set cursor to the `left upper' corner of the screen (1,1). | ||
734 | */ | ||
735 | |||
736 | void TEScreen::home() | ||
737 | { | ||
738 | cuX = 0; | ||
739 | cuY = 0; | ||
740 | } | ||
741 | |||
742 | /*! set cursor to the begin of the current line. | ||
743 | */ | ||
744 | |||
745 | void TEScreen::Return() | ||
746 | { | ||
747 | cuX = 0; | ||
748 | } | ||
749 | |||
750 | /*! returns the current cursor columns. | ||
751 | */ | ||
752 | |||
753 | int TEScreen::getCursorX() | ||
754 | { | ||
755 | return cuX; | ||
756 | } | ||
757 | |||
758 | /*! returns the current cursor line. | ||
759 | */ | ||
760 | |||
761 | int TEScreen::getCursorY() | ||
762 | { | ||
763 | return cuY; | ||
764 | } | ||
765 | |||
766 | // Erasing --------------------------------------------------------------------- | ||
767 | |||
768 | /*! \section Erasing | ||
769 | |||
770 | This group of operations erase parts of the screen contents by filling | ||
771 | it with spaces colored due to the current rendition settings. | ||
772 | |||
773 | Althought the cursor position is involved in most of these operations, | ||
774 | it is never modified by them. | ||
775 | */ | ||
776 | |||
777 | /*! fill screen between (including) `loca' and `loce' with spaces. | ||
778 | |||
779 | This is an internal helper functions. The parameter types are internal | ||
780 | addresses of within the screen image and make use of the way how the | ||
781 | screen matrix is mapped to the image vector. | ||
782 | */ | ||
783 | |||
784 | void TEScreen::clearImage(int loca, int loce, char c) | ||
785 | { int i; | ||
786 | int scr_TL=loc(0,hist.getLines()); | ||
787 | //FIXME: check positions | ||
788 | |||
789 | //Clear entire selection if it overlaps region to be moved... | ||
790 | if ( (sel_BR > (loca+scr_TL) )&&(sel_TL < (loce+scr_TL)) ) | ||
791 | { | ||
792 | clearSelection(); | ||
793 | } | ||
794 | for (i = loca; i <= loce; i++) | ||
795 | { | ||
796 | image[i].c = c; | ||
797 | image[i].f = ef_fg; //DEFAULT_FORE_COLOR; //FIXME: xterm and linux/ansi | ||
798 | image[i].b = ef_bg; //DEFAULT_BACK_COLOR; // many have different | ||
799 | image[i].r = ef_re; //DEFAULT_RENDITION; // ideas here. | ||
800 | } | ||
801 | } | ||
802 | |||
803 | /*! move image between (including) `loca' and `loce' to 'dst'. | ||
804 | |||
805 | This is an internal helper functions. The parameter types are internal | ||
806 | addresses of within the screen image and make use of the way how the | ||
807 | screen matrix is mapped to the image vector. | ||
808 | */ | ||
809 | |||
810 | void TEScreen::moveImage(int dst, int loca, int loce) | ||
811 | { | ||
812 | //FIXME: check positions | ||
813 | if (loce < loca) { | ||
814 | // kdDebug() << "WARNING!!! call to TEScreen:moveImage with loce < loca!" << endl; | ||
815 | return; | ||
816 | } | ||
817 | memmove(&image[dst],&image[loca],(loce-loca+1)*sizeof(ca)); | ||
818 | } | ||
819 | |||
820 | /*! clear from (including) current cursor position to end of screen. | ||
821 | */ | ||
822 | |||
823 | void TEScreen::clearToEndOfScreen() | ||
824 | { | ||
825 | clearImage(loc(cuX,cuY),loc(columns-1,lines-1),' '); | ||
826 | } | ||
827 | |||
828 | /*! clear from begin of screen to (including) current cursor position. | ||
829 | */ | ||
830 | |||
831 | void TEScreen::clearToBeginOfScreen() | ||
832 | { | ||
833 | clearImage(loc(0,0),loc(cuX,cuY),' '); | ||
834 | } | ||
835 | |||
836 | /*! clear the entire screen. | ||
837 | */ | ||
838 | |||
839 | void TEScreen::clearEntireScreen() | ||
840 | { | ||
841 | clearImage(loc(0,0),loc(columns-1,lines-1),' '); | ||
842 | } | ||
843 | |||
844 | /*! fill screen with 'E' | ||
845 | This is to aid screen alignment | ||
846 | */ | ||
847 | |||
848 | void TEScreen::helpAlign() | ||
849 | { | ||
850 | clearImage(loc(0,0),loc(columns-1,lines-1),'E'); | ||
851 | } | ||
852 | |||
853 | /*! clear from (including) current cursor position to end of current cursor line. | ||
854 | */ | ||
855 | |||
856 | void TEScreen::clearToEndOfLine() | ||
857 | { | ||
858 | clearImage(loc(cuX,cuY),loc(columns-1,cuY),' '); | ||
859 | } | ||
860 | |||
861 | /*! clear from begin of current cursor line to (including) current cursor position. | ||
862 | */ | ||
863 | |||
864 | void TEScreen::clearToBeginOfLine() | ||
865 | { | ||
866 | clearImage(loc(0,cuY),loc(cuX,cuY),' '); | ||
867 | } | ||
868 | |||
869 | /*! clears entire current cursor line | ||
870 | */ | ||
871 | |||
872 | void TEScreen::clearEntireLine() | ||
873 | { | ||
874 | clearImage(loc(0,cuY),loc(columns-1,cuY),' '); | ||
875 | } | ||
876 | |||
877 | // Rendition ------------------------------------------------------------------ | ||
878 | |||
879 | /*! | ||
880 | set rendition mode | ||
881 | */ | ||
882 | |||
883 | void TEScreen::setRendition(int re) | ||
884 | { | ||
885 | cu_re |= re; | ||
886 | effectiveRendition(); | ||
887 | } | ||
888 | |||
889 | /*! | ||
890 | reset rendition mode | ||
891 | */ | ||
892 | |||
893 | void TEScreen::resetRendition(int re) | ||
894 | { | ||
895 | cu_re &= ~re; | ||
896 | effectiveRendition(); | ||
897 | } | ||
898 | |||
899 | /*! | ||
900 | */ | ||
901 | |||
902 | void TEScreen::setDefaultRendition() | ||
903 | { | ||
904 | setForeColorToDefault(); | ||
905 | setBackColorToDefault(); | ||
906 | cu_re = DEFAULT_RENDITION; | ||
907 | effectiveRendition(); | ||
908 | } | ||
909 | |||
910 | /*! | ||
911 | */ | ||
912 | |||
913 | void TEScreen::setForeColor(int fgcolor) | ||
914 | { | ||
915 | cu_fg = (fgcolor&7)+((fgcolor&8) ? 4+8 : 2); | ||
916 | effectiveRendition(); | ||
917 | } | ||
918 | |||
919 | /*! | ||
920 | */ | ||
921 | |||
922 | void TEScreen::setBackColor(int bgcolor) | ||
923 | { | ||
924 | cu_bg = (bgcolor&7)+((bgcolor&8) ? 4+8 : 2); | ||
925 | effectiveRendition(); | ||
926 | } | ||
927 | |||
928 | /*! | ||
929 | */ | ||
930 | |||
931 | void TEScreen::setBackColorToDefault() | ||
932 | { | ||
933 | cu_bg = DEFAULT_BACK_COLOR; | ||
934 | effectiveRendition(); | ||
935 | } | ||
936 | |||
937 | /*! | ||
938 | */ | ||
939 | |||
940 | void TEScreen::setForeColorToDefault() | ||
941 | { | ||
942 | cu_fg = DEFAULT_FORE_COLOR; | ||
943 | effectiveRendition(); | ||
944 | } | ||
945 | |||
946 | /* ------------------------------------------------------------------------- */ | ||
947 | /* */ | ||
948 | /* Marking & Selection */ | ||
949 | /* */ | ||
950 | /* ------------------------------------------------------------------------- */ | ||
951 | |||
952 | void TEScreen::clearSelection() | ||
953 | { | ||
954 | sel_BR = -1; | ||
955 | sel_TL = -1; | ||
956 | sel_begin = -1; | ||
957 | } | ||
958 | |||
959 | void TEScreen::setSelBeginXY(const int x, const int y) | ||
960 | { | ||
961 | sel_begin = loc(x,y+histCursor) ; | ||
962 | sel_BR = sel_begin; | ||
963 | sel_TL = sel_begin; | ||
964 | } | ||
965 | |||
966 | void TEScreen::setSelExtentXY(const int x, const int y) | ||
967 | { | ||
968 | if (sel_begin == -1) return; | ||
969 | int l = loc(x,y + histCursor); | ||
970 | |||
971 | if (l < sel_begin) | ||
972 | { | ||
973 | sel_TL = l; | ||
974 | sel_BR = sel_begin; | ||
975 | } | ||
976 | else | ||
977 | { | ||
978 | /* FIXME, HACK to correct for x too far to the right... */ | ||
979 | if (( x == columns )|| (x == 0)) l--; | ||
980 | |||
981 | sel_TL = sel_begin; | ||
982 | sel_BR = l; | ||
983 | } | ||
984 | } | ||
985 | |||
986 | QString TEScreen::getSelText(const BOOL preserve_line_breaks) | ||
987 | { | ||
988 | if (sel_begin == -1) | ||
989 | return QString::null; // Selection got clear while selecting. | ||
990 | |||
991 | int *m; // buffer to fill. | ||
992 | int s, d; // source index, dest. index. | ||
993 | int hist_BR = loc(0, hist.getLines()); | ||
994 | int hY = sel_TL / columns; | ||
995 | int hX = sel_TL % columns; | ||
996 | int eol; // end of line | ||
997 | |||
998 | s = sel_TL; // tracks copy in source. | ||
999 | |||
1000 | // allocate buffer for maximum | ||
1001 | // possible size... | ||
1002 | d = (sel_BR - sel_TL) / columns + 1; | ||
1003 | m = new int[d * (columns + 1) + 2]; | ||
1004 | d = 0; | ||
1005 | |||
1006 | while (s <= sel_BR) | ||
1007 | { | ||
1008 | if (s < hist_BR) | ||
1009 | { // get lines from hist.history | ||
1010 | // buffer. | ||
1011 | eol = hist.getLineLen(hY); | ||
1012 | |||
1013 | if ((hY == (sel_BR / columns)) && | ||
1014 | (eol >= (sel_BR % columns))) | ||
1015 | { | ||
1016 | eol = sel_BR % columns + 1; | ||
1017 | } | ||
1018 | |||
1019 | while (hX < eol) | ||
1020 | { | ||
1021 | m[d++] = hist.getCell(hY, hX++).c; | ||
1022 | s++; | ||
1023 | } | ||
1024 | |||
1025 | if (s <= sel_BR) | ||
1026 | { | ||
1027 | // The line break handling | ||
1028 | // It's different from the screen | ||
1029 | // image case! | ||
1030 | if (eol % columns == 0) | ||
1031 | { | ||
1032 | // That's either a completely filled | ||
1033 | // line or an empty line | ||
1034 | if (eol == 0) | ||
1035 | { | ||
1036 | m[d++] = '\n'; | ||
1037 | } | ||
1038 | else | ||
1039 | { | ||
1040 | // We have a full line. | ||
1041 | // FIXME: How can we handle newlines | ||
1042 | // at this position?! | ||
1043 | } | ||
1044 | } | ||
1045 | else if ((eol + 1) % columns == 0) | ||
1046 | { | ||
1047 | // FIXME: We don't know if this was a | ||
1048 | // space at the last position or a | ||
1049 | // short line!! | ||
1050 | m[d++] = ' '; | ||
1051 | } | ||
1052 | else | ||
1053 | { | ||
1054 | // We have a short line here. Put a | ||
1055 | // newline or a space into the | ||
1056 | // buffer. | ||
1057 | m[d++] = preserve_line_breaks ? '\n' : ' '; | ||
1058 | } | ||
1059 | } | ||
1060 | |||
1061 | hY++; | ||
1062 | hX = 0; | ||
1063 | s = hY * columns; | ||
1064 | } | ||
1065 | else | ||
1066 | { // or from screen image. | ||
1067 | eol = (s / columns + 1) * columns - 1; | ||
1068 | |||
1069 | if (eol < sel_BR) | ||
1070 | { | ||
1071 | while ((eol > s) && | ||
1072 | isspace(image[eol - hist_BR].c)) | ||
1073 | { | ||
1074 | eol--; | ||
1075 | } | ||
1076 | } | ||
1077 | else | ||
1078 | { | ||
1079 | eol = sel_BR; | ||
1080 | } | ||
1081 | |||
1082 | while (s <= eol) | ||
1083 | { | ||
1084 | m[d++] = image[s++ - hist_BR].c; | ||
1085 | } | ||
1086 | |||
1087 | if (eol < sel_BR) | ||
1088 | { | ||
1089 | // eol processing see below ... | ||
1090 | if ((eol + 1) % columns == 0) | ||
1091 | { | ||
1092 | if (image[eol - hist_BR].c == ' ') | ||
1093 | { | ||
1094 | m[d++] = ' '; | ||
1095 | } | ||
1096 | } | ||
1097 | else | ||
1098 | { | ||
1099 | m[d++] = ((preserve_line_breaks || | ||
1100 | ((eol % columns) == 0)) ? | ||
1101 | '\n' : ' '); | ||
1102 | } | ||
1103 | } | ||
1104 | |||
1105 | s = (eol / columns + 1) * columns; | ||
1106 | } | ||
1107 | } | ||
1108 | |||
1109 | QChar* qc = new QChar[d]; | ||
1110 | |||
1111 | for (int i = 0; i < d; i++) | ||
1112 | { | ||
1113 | qc[i] = m[i]; | ||
1114 | } | ||
1115 | |||
1116 | QString res(qc, d); | ||
1117 | |||
1118 | delete m; | ||
1119 | delete qc; | ||
1120 | |||
1121 | return res; | ||
1122 | } | ||
1123 | /* above ... end of line processing for selection -- psilva | ||
1124 | cases: | ||
1125 | |||
1126 | 1) (eol+1)%columns == 0 --> the whole line is filled. | ||
1127 | If the last char is a space, insert (preserve) space. otherwise | ||
1128 | leave the text alone, so that words that are broken by linewrap | ||
1129 | are preserved. | ||
1130 | |||
1131 | FIXME: | ||
1132 | * this suppresses \n for command output that is | ||
1133 | sized to the exact column width of the screen. | ||
1134 | |||
1135 | 2) eol%columns == 0 --> blank line. | ||
1136 | insert a \n unconditionally. | ||
1137 | Do it either you would because you are in preserve_line_break mode, | ||
1138 | or because it's an ASCII paragraph delimiter, so even when | ||
1139 | not preserving line_breaks, you want to preserve paragraph breaks. | ||
1140 | |||
1141 | 3) else --> partially filled line | ||
1142 | insert a \n in preserve line break mode, else a space | ||
1143 | The space prevents concatenation of the last word of one | ||
1144 | line with the first of the next. | ||
1145 | |||
1146 | */ | ||
1147 | |||
1148 | void TEScreen::addHistLine() | ||
1149 | { | ||
1150 | assert(hasScroll() || histCursor == 0); | ||
1151 | |||
1152 | // add to hist buffer | ||
1153 | // we have to take care about scrolling, too... | ||
1154 | |||
1155 | if (hasScroll()) | ||
1156 | { ca dft; | ||
1157 | |||
1158 | int end = columns-1; | ||
1159 | while (end >= 0 && image[end] == dft) | ||
1160 | end -= 1; | ||
1161 | |||
1162 | hist.addCells(image,end+1); | ||
1163 | hist.addLine(); | ||
1164 | |||
1165 | // adjust history cursor | ||
1166 | histCursor += (hist.getLines()-1 == histCursor); | ||
1167 | } | ||
1168 | |||
1169 | if (!hasScroll()) histCursor = 0; //FIXME: a poor workaround | ||
1170 | } | ||
1171 | |||
1172 | void TEScreen::setHistCursor(int cursor) | ||
1173 | { | ||
1174 | histCursor = cursor; //FIXME:rangecheck | ||
1175 | } | ||
1176 | |||
1177 | int TEScreen::getHistCursor() | ||
1178 | { | ||
1179 | return histCursor; | ||
1180 | } | ||
1181 | |||
1182 | int TEScreen::getHistLines() | ||
1183 | { | ||
1184 | return hist.getLines(); | ||
1185 | } | ||
1186 | |||
1187 | void TEScreen::setScroll(bool on) | ||
1188 | { | ||
1189 | histCursor = 0; | ||
1190 | clearSelection(); | ||
1191 | hist.setScroll(on); | ||
1192 | } | ||
1193 | |||
1194 | bool TEScreen::hasScroll() | ||
1195 | { | ||
1196 | return hist.hasScroll(); | ||
1197 | } | ||
diff --git a/core/apps/embeddedkonsole/TEScreen.h b/core/apps/embeddedkonsole/TEScreen.h new file mode 100644 index 0000000..ba47ee5 --- a/dev/null +++ b/core/apps/embeddedkonsole/TEScreen.h | |||
@@ -0,0 +1,259 @@ | |||
1 | /* -------------------------------------------------------------------------- */ | ||
2 | /* */ | ||
3 | /* [te_screen.h] Screen Data Type */ | ||
4 | /* */ | ||
5 | /* -------------------------------------------------------------------------- */ | ||
6 | /* */ | ||
7 | /* Copyright (c) 1997,1998 by Lars Doelle <lars.doelle@on-line.de> */ | ||
8 | /* */ | ||
9 | /* This file is part of Konsole - an X terminal for KDE */ | ||
10 | /* */ | ||
11 | /* -------------------------------------------------------------------------- */ | ||
12 | /* */ | ||
13 | /* Ported Konsole to Qt/Embedded */ | ||
14 | /* */ | ||
15 | /* Copyright (C) 2000 by John Ryland <jryland@trolltech.com> */ | ||
16 | /* */ | ||
17 | /* -------------------------------------------------------------------------- */ | ||
18 | |||
19 | #ifndef TESCREEN_H | ||
20 | #define TESCREEN_H | ||
21 | |||
22 | /*! \file | ||
23 | */ | ||
24 | |||
25 | #include "TECommon.h" | ||
26 | #include "TEHistory.h" | ||
27 | |||
28 | #define MODE_Origin 0 | ||
29 | #define MODE_Wrap 1 | ||
30 | #define MODE_Insert 2 | ||
31 | #define MODE_Screen 3 | ||
32 | #define MODE_Cursor 4 | ||
33 | #define MODE_NewLine 5 | ||
34 | #define MODES_SCREEN 6 | ||
35 | |||
36 | /*! | ||
37 | */ | ||
38 | struct ScreenParm | ||
39 | { | ||
40 | int mode[MODES_SCREEN]; | ||
41 | }; | ||
42 | |||
43 | |||
44 | class TEScreen | ||
45 | { | ||
46 | public: | ||
47 | TEScreen(int lines, int columns); | ||
48 | ~TEScreen(); | ||
49 | |||
50 | public: // these are all `Screen' operations | ||
51 | // | ||
52 | // VT100/2 Operations ------------------ | ||
53 | // | ||
54 | // Cursor Movement | ||
55 | // | ||
56 | void cursorUp (int n); | ||
57 | void cursorDown (int n); | ||
58 | void cursorLeft (int n); | ||
59 | void cursorRight (int n); | ||
60 | void setCursorY (int y); | ||
61 | void setCursorX (int x); | ||
62 | void setCursorYX (int y, int x); | ||
63 | void setMargins (int t, int b); | ||
64 | // | ||
65 | // Cursor Movement with Scrolling | ||
66 | // | ||
67 | void NewLine (); | ||
68 | void NextLine (); | ||
69 | void index (); | ||
70 | void reverseIndex(); | ||
71 | // | ||
72 | void Return (); | ||
73 | void BackSpace (); | ||
74 | void Tabulate (); | ||
75 | // | ||
76 | // Editing | ||
77 | // | ||
78 | void eraseChars (int n); | ||
79 | void deleteChars (int n); | ||
80 | void insertChars (int n); | ||
81 | void deleteLines (int n); | ||
82 | void insertLines (int n); | ||
83 | // | ||
84 | // ------------------------------------- | ||
85 | // | ||
86 | void clearTabStops(); | ||
87 | void changeTabStop(bool set); | ||
88 | // | ||
89 | void resetMode (int n); | ||
90 | void setMode (int n); | ||
91 | void saveMode (int n); | ||
92 | void restoreMode (int n); | ||
93 | // | ||
94 | void saveCursor (); | ||
95 | void restoreCursor(); | ||
96 | // | ||
97 | // ------------------------------------- | ||
98 | // | ||
99 | void clearEntireScreen(); | ||
100 | void clearToEndOfScreen(); | ||
101 | void clearToBeginOfScreen(); | ||
102 | // | ||
103 | void clearEntireLine(); | ||
104 | void clearToEndOfLine(); | ||
105 | void clearToBeginOfLine(); | ||
106 | // | ||
107 | void helpAlign (); | ||
108 | // | ||
109 | // ------------------------------------- | ||
110 | // | ||
111 | void setRendition (int rendition); | ||
112 | void resetRendition(int rendition); | ||
113 | void setForeColor (int fgcolor); | ||
114 | void setBackColor (int bgcolor); | ||
115 | // | ||
116 | void setDefaultRendition(); | ||
117 | void setForeColorToDefault(); | ||
118 | void setBackColorToDefault(); | ||
119 | // | ||
120 | // ------------------------------------- | ||
121 | // | ||
122 | BOOL getMode (int n); | ||
123 | // | ||
124 | // only for report cursor position | ||
125 | // | ||
126 | int getCursorX(); | ||
127 | int getCursorY(); | ||
128 | // | ||
129 | // ------------------------------------- | ||
130 | // | ||
131 | void clear(); | ||
132 | void home(); | ||
133 | void reset(); | ||
134 | // | ||
135 | void ShowCharacter(unsigned short c); | ||
136 | // | ||
137 | void resizeImage(int new_lines, int new_columns); | ||
138 | // | ||
139 | ca* getCookedImage(); | ||
140 | |||
141 | /*! return the number of lines. */ | ||
142 | int getLines() { return lines; } | ||
143 | /*! return the number of columns. */ | ||
144 | int getColumns() { return columns; } | ||
145 | |||
146 | /*! set the position of the history cursor. */ | ||
147 | void setHistCursor(int cursor); | ||
148 | /*! return the position of the history cursor. */ | ||
149 | int getHistCursor(); | ||
150 | |||
151 | int getHistLines (); | ||
152 | void setScroll(bool on); | ||
153 | bool hasScroll(); | ||
154 | |||
155 | // | ||
156 | // Selection | ||
157 | // | ||
158 | void setSelBeginXY(const int x, const int y); | ||
159 | void setSelExtentXY(const int x, const int y); | ||
160 | void clearSelection(); | ||
161 | QString getSelText(const BOOL preserve_line_breaks); | ||
162 | |||
163 | void checkSelection(int from, int to); | ||
164 | |||
165 | private: // helper | ||
166 | |||
167 | void clearImage(int loca, int loce, char c); | ||
168 | void moveImage(int dst, int loca, int loce); | ||
169 | |||
170 | void scrollUp(int from, int i); | ||
171 | void scrollDown(int from, int i); | ||
172 | |||
173 | void addHistLine(); | ||
174 | |||
175 | void initTabStops(); | ||
176 | |||
177 | void effectiveRendition(); | ||
178 | void reverseRendition(ca* p); | ||
179 | |||
180 | private: | ||
181 | |||
182 | /* | ||
183 | The state of the screen is more complex as one would | ||
184 | expect first. The screem does really do part of the | ||
185 | emulation providing state informations in form of modes, | ||
186 | margins, tabulators, cursor etc. | ||
187 | |||
188 | Even more unexpected are variables to save and restore | ||
189 | parts of the state. | ||
190 | */ | ||
191 | |||
192 | // screen image ---------------- | ||
193 | |||
194 | int lines; | ||
195 | int columns; | ||
196 | ca *image; // [lines][columns] | ||
197 | |||
198 | // history buffer --------------- | ||
199 | |||
200 | int histCursor; // display position relative to start of the history buffer | ||
201 | HistoryScroll hist; | ||
202 | |||
203 | // cursor location | ||
204 | |||
205 | int cuX; | ||
206 | int cuY; | ||
207 | |||
208 | // cursor color and rendition info | ||
209 | |||
210 | UINT8 cu_fg; // foreground | ||
211 | UINT8 cu_bg; // background | ||
212 | UINT8 cu_re; // rendition | ||
213 | |||
214 | // margins ---------------- | ||
215 | |||
216 | int tmargin; // top margin | ||
217 | int bmargin; // bottom margin | ||
218 | |||
219 | // states ---------------- | ||
220 | |||
221 | ScreenParm currParm; | ||
222 | |||
223 | // ---------------------------- | ||
224 | |||
225 | bool* tabstops; | ||
226 | |||
227 | // selection ------------------- | ||
228 | |||
229 | int sel_begin; // The first location selected. | ||
230 | int sel_TL; // TopLeft Location. | ||
231 | int sel_BR; // Bottom Right Location. | ||
232 | |||
233 | // effective colors and rendition ------------ | ||
234 | |||
235 | UINT8 ef_fg; // These are derived from | ||
236 | UINT8 ef_bg; // the cu_* variables above | ||
237 | UINT8 ef_re; // to speed up operation | ||
238 | |||
239 | // | ||
240 | // save cursor, rendition & states ------------ | ||
241 | // | ||
242 | |||
243 | // cursor location | ||
244 | |||
245 | int sa_cuX; | ||
246 | int sa_cuY; | ||
247 | |||
248 | // rendition info | ||
249 | |||
250 | UINT8 sa_cu_re; | ||
251 | UINT8 sa_cu_fg; | ||
252 | UINT8 sa_cu_bg; | ||
253 | |||
254 | // modes | ||
255 | |||
256 | ScreenParm saveParm; | ||
257 | }; | ||
258 | |||
259 | #endif // TESCREEN_H | ||
diff --git a/core/apps/embeddedkonsole/TEWidget.cpp b/core/apps/embeddedkonsole/TEWidget.cpp new file mode 100644 index 0000000..dc83998 --- a/dev/null +++ b/core/apps/embeddedkonsole/TEWidget.cpp | |||
@@ -0,0 +1,1243 @@ | |||
1 | /* ------------------------------------------------------------------------ */ | ||
2 | /* */ | ||
3 | /* [TEWidget.C] Terminal Emulation Widget */ | ||
4 | /* */ | ||
5 | /* ------------------------------------------------------------------------ */ | ||
6 | /* */ | ||
7 | /* Copyright (c) 1997,1998 by Lars Doelle <lars.doelle@on-line.de> */ | ||
8 | /* */ | ||
9 | /* This file is part of Konsole - an X terminal for KDE */ | ||
10 | /* */ | ||
11 | /* ------------------------------------------------------------------------ */ | ||
12 | /* */ | ||
13 | /* Ported Konsole to Qt/Embedded */ | ||
14 | /* */ | ||
15 | /* Copyright (C) 2000 by John Ryland <jryland@trolltech.com> */ | ||
16 | /* */ | ||
17 | /* -------------------------------------------------------------------------- */ | ||
18 | |||
19 | /*! \class TEWidget | ||
20 | |||
21 | \brief Visible screen contents | ||
22 | |||
23 | This class is responsible to map the `image' of a terminal emulation to the | ||
24 | display. All the dependency of the emulation to a specific GUI or toolkit is | ||
25 | localized here. Further, this widget has no knowledge about being part of an | ||
26 | emulation, it simply work within the terminal emulation framework by exposing | ||
27 | size and key events and by being ordered to show a new image. | ||
28 | |||
29 | <ul> | ||
30 | <li> The internal image has the size of the widget (evtl. rounded up) | ||
31 | <li> The external image used in setImage can have any size. | ||
32 | <li> (internally) the external image is simply copied to the internal | ||
33 | when a setImage happens. During a resizeEvent no painting is done | ||
34 | a paintEvent is expected to follow anyway. | ||
35 | </ul> | ||
36 | |||
37 | \sa TEScreen \sa Emulation | ||
38 | */ | ||
39 | |||
40 | /* FIXME: | ||
41 | - 'image' may also be used uninitialized (it isn't in fact) in resizeEvent | ||
42 | - 'font_a' not used in mouse events | ||
43 | - add destructor | ||
44 | */ | ||
45 | |||
46 | /* TODO | ||
47 | - evtl. be sensitive to `paletteChange' while using default colors. | ||
48 | - set different 'rounding' styles? I.e. have a mode to show clipped chars? | ||
49 | */ | ||
50 | |||
51 | // #include "config.h" | ||
52 | #include "TEWidget.h" | ||
53 | #include "session.h" | ||
54 | |||
55 | #include <qcursor.h> | ||
56 | #include <qregexp.h> | ||
57 | #include <qpainter.h> | ||
58 | #include <qclipboard.h> | ||
59 | #include <qstyle.h> | ||
60 | #include <qfile.h> | ||
61 | #include <qdragobject.h> | ||
62 | |||
63 | #include <stdio.h> | ||
64 | #include <stdlib.h> | ||
65 | #include <unistd.h> | ||
66 | #include <ctype.h> | ||
67 | #include <sys/stat.h> | ||
68 | #include <sys/types.h> | ||
69 | #include <signal.h> | ||
70 | |||
71 | #include <assert.h> | ||
72 | |||
73 | // #include "TEWidget.moc" | ||
74 | //#include <kapp.h> | ||
75 | //#include <kcursor.h> | ||
76 | //#include <kurl.h> | ||
77 | //#include <kdebug.h> | ||
78 | //#include <klocale.h> | ||
79 | |||
80 | #define HERE printf("%s(%d): %s\n",__FILE__,__LINE__,__FUNCTION__) | ||
81 | #define HCNT(Name) // { static int cnt = 1; printf("%s(%d): %s %d\n",__FILE__,__LINE__,Name,cnt++); } | ||
82 | |||
83 | #define loc(X,Y) ((Y)*columns+(X)) | ||
84 | |||
85 | //FIXME: the rim should normally be 1, 0 only when running in full screen mode. | ||
86 | #define rimX 0 // left/right rim width | ||
87 | #define rimY 0 // top/bottom rim high | ||
88 | |||
89 | #define SCRWIDTH 16 // width of the scrollbar | ||
90 | |||
91 | #define yMouseScroll 1 | ||
92 | // scroll increment used when dragging selection at top/bottom of window. | ||
93 | |||
94 | /* ------------------------------------------------------------------------- */ | ||
95 | /* */ | ||
96 | /* Colors */ | ||
97 | /* */ | ||
98 | /* ------------------------------------------------------------------------- */ | ||
99 | |||
100 | //FIXME: the default color table is in session.C now. | ||
101 | // We need a way to get rid of this one, here. | ||
102 | static const ColorEntry base_color_table[TABLE_COLORS] = | ||
103 | // The following are almost IBM standard color codes, with some slight | ||
104 | // gamma correction for the dim colors to compensate for bright X screens. | ||
105 | // It contains the 8 ansiterm/xterm colors in 2 intensities. | ||
106 | { | ||
107 | // Fixme: could add faint colors here, also. | ||
108 | // normal | ||
109 | ColorEntry(QColor(0x00,0x00,0x00), 0, 0 ), ColorEntry( QColor(0xB2,0xB2,0xB2), 1, 0 ), // Dfore, Dback | ||
110 | ColorEntry(QColor(0x00,0x00,0x00), 0, 0 ), ColorEntry( QColor(0xB2,0x18,0x18), 0, 0 ), // Black, Red | ||
111 | ColorEntry(QColor(0x18,0xB2,0x18), 0, 0 ), ColorEntry( QColor(0xB2,0x68,0x18), 0, 0 ), // Green, Yellow | ||
112 | ColorEntry(QColor(0x18,0x18,0xB2), 0, 0 ), ColorEntry( QColor(0xB2,0x18,0xB2), 0, 0 ), // Blue, Magenta | ||
113 | ColorEntry(QColor(0x18,0xB2,0xB2), 0, 0 ), ColorEntry( QColor(0xB2,0xB2,0xB2), 0, 0 ), // Cyan, White | ||
114 | // intensiv | ||
115 | ColorEntry(QColor(0x00,0x00,0x00), 0, 1 ), ColorEntry( QColor(0xFF,0xFF,0xFF), 1, 0 ), | ||
116 | ColorEntry(QColor(0x68,0x68,0x68), 0, 0 ), ColorEntry( QColor(0xFF,0x54,0x54), 0, 0 ), | ||
117 | ColorEntry(QColor(0x54,0xFF,0x54), 0, 0 ), ColorEntry( QColor(0xFF,0xFF,0x54), 0, 0 ), | ||
118 | ColorEntry(QColor(0x54,0x54,0xFF), 0, 0 ), ColorEntry( QColor(0xFF,0x54,0xFF), 0, 0 ), | ||
119 | ColorEntry(QColor(0x54,0xFF,0xFF), 0, 0 ), ColorEntry( QColor(0xFF,0xFF,0xFF), 0, 0 ) | ||
120 | }; | ||
121 | |||
122 | /* Note that we use ANSI color order (bgr), while IBMPC color order is (rgb) | ||
123 | |||
124 | Code 0 1 2 3 4 5 6 7 | ||
125 | ----------- ------- ------- ------- ------- ------- ------- ------- ------- | ||
126 | ANSI (bgr) Black Red Green Yellow Blue Magenta Cyan White | ||
127 | IBMPC (rgb) Black Blue Green Cyan Red Magenta Yellow White | ||
128 | */ | ||
129 | |||
130 | QColor TEWidget::getDefaultBackColor() | ||
131 | { | ||
132 | return color_table[DEFAULT_BACK_COLOR].color; | ||
133 | } | ||
134 | |||
135 | const ColorEntry* TEWidget::getColorTable() const | ||
136 | { | ||
137 | return color_table; | ||
138 | } | ||
139 | |||
140 | const QPixmap *TEWidget::backgroundPixmap() | ||
141 | { | ||
142 | static QPixmap *bg = new QPixmap("~/qpim/main/pics/faded_bg.xpm"); | ||
143 | const QPixmap *pm = bg; | ||
144 | return pm; | ||
145 | } | ||
146 | |||
147 | void TEWidget::setColorTable(const ColorEntry table[]) | ||
148 | { | ||
149 | for (int i = 0; i < TABLE_COLORS; i++) color_table[i] = table[i]; | ||
150 | |||
151 | const QPixmap* pm = backgroundPixmap(); | ||
152 | if (!pm) setBackgroundColor(color_table[DEFAULT_BACK_COLOR].color); | ||
153 | update(); | ||
154 | } | ||
155 | |||
156 | //FIXME: add backgroundPixmapChanged. | ||
157 | |||
158 | /* ------------------------------------------------------------------------- */ | ||
159 | /* */ | ||
160 | /* Font */ | ||
161 | /* */ | ||
162 | /* ------------------------------------------------------------------------- */ | ||
163 | |||
164 | /* | ||
165 | The VT100 has 32 special graphical characters. The usual vt100 extended | ||
166 | xterm fonts have these at 0x00..0x1f. | ||
167 | |||
168 | QT's iso mapping leaves 0x00..0x7f without any changes. But the graphicals | ||
169 | come in here as proper unicode characters. | ||
170 | |||
171 | We treat non-iso10646 fonts as VT100 extended and do the requiered mapping | ||
172 | from unicode to 0x00..0x1f. The remaining translation is then left to the | ||
173 | QCodec. | ||
174 | */ | ||
175 | |||
176 | // assert for i in [0..31] : vt100extended(vt100_graphics[i]) == i. | ||
177 | |||
178 | unsigned short vt100_graphics[32] = | ||
179 | { // 0/8 1/9 2/10 3/11 4/12 5/13 6/14 7/15 | ||
180 | 0x0020, 0x25C6, 0x2592, 0x2409, 0x240c, 0x240d, 0x240a, 0x00b0, | ||
181 | 0x00b1, 0x2424, 0x240b, 0x2518, 0x2510, 0x250c, 0x2514, 0x253c, | ||
182 | 0xF800, 0xF801, 0x2500, 0xF803, 0xF804, 0x251c, 0x2524, 0x2534, | ||
183 | 0x252c, 0x2502, 0x2264, 0x2265, 0x03C0, 0x2260, 0x00A3, 0x00b7 | ||
184 | }; | ||
185 | |||
186 | static QChar vt100extended(QChar c) | ||
187 | { | ||
188 | switch (c.unicode()) | ||
189 | { | ||
190 | case 0x25c6 : return 1; | ||
191 | case 0x2592 : return 2; | ||
192 | case 0x2409 : return 3; | ||
193 | case 0x240c : return 4; | ||
194 | case 0x240d : return 5; | ||
195 | case 0x240a : return 6; | ||
196 | case 0x00b0 : return 7; | ||
197 | case 0x00b1 : return 8; | ||
198 | case 0x2424 : return 9; | ||
199 | case 0x240b : return 10; | ||
200 | case 0x2518 : return 11; | ||
201 | case 0x2510 : return 12; | ||
202 | case 0x250c : return 13; | ||
203 | case 0x2514 : return 14; | ||
204 | case 0x253c : return 15; | ||
205 | case 0xf800 : return 16; | ||
206 | case 0xf801 : return 17; | ||
207 | case 0x2500 : return 18; | ||
208 | case 0xf803 : return 19; | ||
209 | case 0xf804 : return 20; | ||
210 | case 0x251c : return 21; | ||
211 | case 0x2524 : return 22; | ||
212 | case 0x2534 : return 23; | ||
213 | case 0x252c : return 24; | ||
214 | case 0x2502 : return 25; | ||
215 | case 0x2264 : return 26; | ||
216 | case 0x2265 : return 27; | ||
217 | case 0x03c0 : return 28; | ||
218 | case 0x2260 : return 29; | ||
219 | case 0x00a3 : return 30; | ||
220 | case 0x00b7 : return 31; | ||
221 | } | ||
222 | return c; | ||
223 | } | ||
224 | |||
225 | static QChar identicalMap(QChar c) | ||
226 | { | ||
227 | return c; | ||
228 | } | ||
229 | |||
230 | void TEWidget::fontChange(const QFont &) | ||
231 | { | ||
232 | QFontMetrics fm(font()); | ||
233 | font_h = fm.height(); | ||
234 | font_w = fm.maxWidth(); | ||
235 | font_a = fm.ascent(); | ||
236 | //printf("font_h: %d\n",font_h); | ||
237 | //printf("font_w: %d\n",font_w); | ||
238 | //printf("font_a: %d\n",font_a); | ||
239 | //printf("charset: %s\n",QFont::encodingName(font().charSet()).ascii()); | ||
240 | //printf("rawname: %s\n",font().rawName().ascii()); | ||
241 | fontMap = | ||
242 | #if QT_VERSION < 300 | ||
243 | strcmp(QFont::encodingName(font().charSet()).ascii(),"iso10646") | ||
244 | ? vt100extended | ||
245 | : | ||
246 | #endif | ||
247 | identicalMap; | ||
248 | propagateSize(); | ||
249 | update(); | ||
250 | } | ||
251 | |||
252 | void TEWidget::setVTFont(const QFont& f) | ||
253 | { | ||
254 | QFrame::setFont(f); | ||
255 | } | ||
256 | |||
257 | QFont TEWidget::getVTFont() | ||
258 | { | ||
259 | return font(); | ||
260 | } | ||
261 | |||
262 | void TEWidget::setFont(const QFont &) | ||
263 | { | ||
264 | // ignore font change request if not coming from konsole itself | ||
265 | } | ||
266 | |||
267 | /* ------------------------------------------------------------------------- */ | ||
268 | /* */ | ||
269 | /* Constructor / Destructor */ | ||
270 | /* */ | ||
271 | /* ------------------------------------------------------------------------- */ | ||
272 | |||
273 | TEWidget::TEWidget(QWidget *parent, const char *name) : QFrame(parent,name) | ||
274 | { | ||
275 | #ifndef QT_NO_CLIPBOARD | ||
276 | cb = QApplication::clipboard(); | ||
277 | QObject::connect( (QObject*)cb, SIGNAL(dataChanged()), | ||
278 | this, SLOT(onClearSelection()) ); | ||
279 | #endif | ||
280 | |||
281 | scrollbar = new QScrollBar(this); | ||
282 | scrollbar->setCursor( arrowCursor ); | ||
283 | connect(scrollbar, SIGNAL(valueChanged(int)), this, SLOT(scrollChanged(int))); | ||
284 | scrollLoc = SCRNONE; | ||
285 | |||
286 | blinkT = new QTimer(this); | ||
287 | connect(blinkT, SIGNAL(timeout()), this, SLOT(blinkEvent())); | ||
288 | // blinking = FALSE; | ||
289 | blinking = TRUE; | ||
290 | |||
291 | resizing = FALSE; | ||
292 | actSel = 0; | ||
293 | image = 0; | ||
294 | lines = 1; | ||
295 | columns = 1; | ||
296 | font_w = 1; | ||
297 | font_h = 1; | ||
298 | font_a = 1; | ||
299 | word_selection_mode = FALSE; | ||
300 | |||
301 | setMouseMarks(TRUE); | ||
302 | setVTFont( QFont("fixed") ); | ||
303 | setColorTable(base_color_table); // init color table | ||
304 | |||
305 | qApp->installEventFilter( this ); //FIXME: see below | ||
306 | // KCursor::setAutoHideCursor( this, true ); | ||
307 | |||
308 | // Init DnD //////////////////////////////////////////////////////////////// | ||
309 | currentSession = NULL; | ||
310 | // setAcceptDrops(true); // attempt | ||
311 | // m_drop = new QPopupMenu(this); | ||
312 | // m_drop->insertItem( QString("Paste"), 0); | ||
313 | // m_drop->insertItem( QString("cd"), 1); | ||
314 | // connect(m_drop, SIGNAL(activated(int)), SLOT(drop_menu_activated(int))); | ||
315 | |||
316 | // we need focus so that the auto-hide cursor feature works | ||
317 | setFocus(); | ||
318 | setFocusPolicy( WheelFocus ); | ||
319 | } | ||
320 | |||
321 | //FIXME: make proper destructor | ||
322 | // Here's a start (David) | ||
323 | TEWidget::~TEWidget() | ||
324 | { | ||
325 | qApp->removeEventFilter( this ); | ||
326 | if (image) free(image); | ||
327 | } | ||
328 | |||
329 | /* ------------------------------------------------------------------------- */ | ||
330 | /* */ | ||
331 | /* Display Operations */ | ||
332 | /* */ | ||
333 | /* ------------------------------------------------------------------------- */ | ||
334 | |||
335 | /*! | ||
336 | attributed string draw primitive | ||
337 | */ | ||
338 | |||
339 | void TEWidget::drawAttrStr(QPainter &paint, QRect rect, | ||
340 | QString& str, ca attr, BOOL pm, BOOL clear) | ||
341 | { | ||
342 | if (pm && color_table[attr.b].transparent) | ||
343 | { | ||
344 | paint.setBackgroundMode( TransparentMode ); | ||
345 | if (clear) erase(rect); | ||
346 | } | ||
347 | else | ||
348 | { | ||
349 | if (blinking) | ||
350 | paint.fillRect(rect, color_table[attr.b].color); | ||
351 | else | ||
352 | { | ||
353 | paint.setBackgroundMode( OpaqueMode ); | ||
354 | paint.setBackgroundColor( color_table[attr.b].color ); | ||
355 | } | ||
356 | } | ||
357 | |||
358 | if (color_table[attr.f].bold) | ||
359 | paint.setPen(QColor( 0x8F, 0x00, 0x00 )); | ||
360 | else | ||
361 | paint.setPen(color_table[attr.f].color); | ||
362 | |||
363 | paint.drawText(rect.x(),rect.y()+font_a, str); | ||
364 | |||
365 | if (attr.r & RE_UNDERLINE) | ||
366 | paint.drawLine(rect.left(), rect.y()+font_a+1, rect.right(),rect.y()+font_a+1 ); | ||
367 | } | ||
368 | |||
369 | /*! | ||
370 | The image can only be set completely. | ||
371 | |||
372 | The size of the new image may or may not match the size of the widget. | ||
373 | */ | ||
374 | |||
375 | void TEWidget::setImage(const ca* const newimg, int lines, int columns) | ||
376 | { int y,x,len; | ||
377 | const QPixmap* pm = backgroundPixmap(); | ||
378 | QPainter paint; | ||
379 | setUpdatesEnabled(FALSE); | ||
380 | paint.begin( this ); | ||
381 | HCNT("setImage"); | ||
382 | |||
383 | QPoint tL = contentsRect().topLeft(); | ||
384 | int tLx = tL.x(); | ||
385 | int tLy = tL.y(); | ||
386 | hasBlinker = FALSE; | ||
387 | |||
388 | int cf = -1; // undefined | ||
389 | int cb = -1; // undefined | ||
390 | int cr = -1; // undefined | ||
391 | |||
392 | int lins = QMIN(this->lines, QMAX(0,lines )); | ||
393 | int cols = QMIN(this->columns,QMAX(0,columns)); | ||
394 | QChar *disstrU = new QChar[cols]; | ||
395 | |||
396 | //{ static int cnt = 0; printf("setImage %d\n",cnt++); } | ||
397 | for (y = 0; y < lins; y++) | ||
398 | { | ||
399 | const ca* lcl = &image[y*this->columns]; | ||
400 | const ca* const ext = &newimg[y*columns]; | ||
401 | if (!resizing) // not while resizing, we're expecting a paintEvent | ||
402 | for (x = 0; x < cols; x++) | ||
403 | { | ||
404 | hasBlinker |= (ext[x].r & RE_BLINK); | ||
405 | if (ext[x] != lcl[x]) | ||
406 | { | ||
407 | cr = ext[x].r; | ||
408 | cb = ext[x].b; | ||
409 | if (ext[x].f != cf) cf = ext[x].f; | ||
410 | int lln = cols - x; | ||
411 | disstrU[0] = fontMap(ext[x+0].c); | ||
412 | for (len = 1; len < lln; len++) | ||
413 | { | ||
414 | if (ext[x+len].f != cf || ext[x+len].b != cb || ext[x+len].r != cr || | ||
415 | ext[x+len] == lcl[x+len] ) | ||
416 | break; | ||
417 | disstrU[len] = fontMap(ext[x+len].c); | ||
418 | } | ||
419 | QString unistr(disstrU,len); | ||
420 | drawAttrStr(paint, | ||
421 | QRect(blX+tLx+font_w*x,bY+tLy+font_h*y,font_w*len,font_h), | ||
422 | unistr, ext[x], pm != NULL, true); | ||
423 | x += len - 1; | ||
424 | } | ||
425 | } | ||
426 | // finally, make `image' become `newimg'. | ||
427 | memcpy((void*)lcl,(const void*)ext,cols*sizeof(ca)); | ||
428 | } | ||
429 | drawFrame( &paint ); | ||
430 | paint.end(); | ||
431 | setUpdatesEnabled(TRUE); | ||
432 | if ( hasBlinker && !blinkT->isActive()) blinkT->start(1000); // 1000 ms | ||
433 | if (!hasBlinker && blinkT->isActive()) { blinkT->stop(); blinking = FALSE; } | ||
434 | delete [] disstrU; | ||
435 | } | ||
436 | |||
437 | // paint Event //////////////////////////////////////////////////// | ||
438 | |||
439 | /*! | ||
440 | The difference of this routine vs. the `setImage' is, | ||
441 | that the drawing does not include a difference analysis | ||
442 | between the old and the new image. Instead, the internal | ||
443 | image is used and the painting bound by the PaintEvent box. | ||
444 | */ | ||
445 | |||
446 | void TEWidget::paintEvent( QPaintEvent* pe ) | ||
447 | { | ||
448 | |||
449 | //{ static int cnt = 0; printf("paint %d\n",cnt++); } | ||
450 | const QPixmap* pm = backgroundPixmap(); | ||
451 | QPainter paint; | ||
452 | setUpdatesEnabled(FALSE); | ||
453 | paint.begin( this ); | ||
454 | paint.setBackgroundMode( TransparentMode ); | ||
455 | HCNT("paintEvent"); | ||
456 | |||
457 | // Note that the actual widget size can be slightly larger | ||
458 | // that the image (the size is truncated towards the smaller | ||
459 | // number of characters in `resizeEvent'. The paint rectangle | ||
460 | // can thus be larger than the image, but less then the size | ||
461 | // of one character. | ||
462 | |||
463 | QRect rect = pe->rect().intersect(contentsRect()); | ||
464 | |||
465 | QPoint tL = contentsRect().topLeft(); | ||
466 | int tLx = tL.x(); | ||
467 | int tLy = tL.y(); | ||
468 | |||
469 | int lux = QMIN(columns-1, QMAX(0,(rect.left() - tLx - blX ) / font_w)); | ||
470 | int luy = QMIN(lines-1, QMAX(0,(rect.top() - tLy - bY ) / font_h)); | ||
471 | int rlx = QMIN(columns-1, QMAX(0,(rect.right() - tLx - blX ) / font_w)); | ||
472 | int rly = QMIN(lines-1, QMAX(0,(rect.bottom() - tLy - bY ) / font_h)); | ||
473 | |||
474 | /* | ||
475 | printf("paintEvent: %d..%d, %d..%d (%d..%d, %d..%d)\n",lux,rlx,luy,rly, | ||
476 | rect.left(), rect.right(), rect.top(), rect.bottom()); | ||
477 | */ | ||
478 | |||
479 | // if (pm != NULL && color_table[image->b].transparent) | ||
480 | // erase(rect); | ||
481 | // BL: I have no idea why we need this, and it breaks the refresh. | ||
482 | |||
483 | QChar *disstrU = new QChar[columns]; | ||
484 | for (int y = luy; y <= rly; y++) | ||
485 | for (int x = lux; x <= rlx; x++) | ||
486 | { | ||
487 | int len = 1; | ||
488 | disstrU[0] = fontMap(image[loc(x,y)].c); | ||
489 | int cf = image[loc(x,y)].f; | ||
490 | int cb = image[loc(x,y)].b; | ||
491 | int cr = image[loc(x,y)].r; | ||
492 | while (x+len <= rlx && | ||
493 | image[loc(x+len,y)].f == cf && | ||
494 | image[loc(x+len,y)].b == cb && | ||
495 | image[loc(x+len,y)].r == cr ) | ||
496 | { | ||
497 | disstrU[len] = fontMap(image[loc(x+len,y)].c); | ||
498 | len += 1; | ||
499 | } | ||
500 | QString unistr(disstrU,len); | ||
501 | drawAttrStr(paint, | ||
502 | QRect(blX+tLx+font_w*x,bY+tLy+font_h*y,font_w*len,font_h), | ||
503 | unistr, image[loc(x,y)], pm != NULL, false); | ||
504 | x += len - 1; | ||
505 | } | ||
506 | delete [] disstrU; | ||
507 | drawFrame( &paint ); | ||
508 | paint.end(); | ||
509 | setUpdatesEnabled(TRUE); | ||
510 | } | ||
511 | |||
512 | void TEWidget::blinkEvent() | ||
513 | { | ||
514 | blinking = !blinking; | ||
515 | repaint(FALSE); | ||
516 | } | ||
517 | |||
518 | /* ------------------------------------------------------------------------- */ | ||
519 | /* */ | ||
520 | /* Resizing */ | ||
521 | /* */ | ||
522 | /* ------------------------------------------------------------------------- */ | ||
523 | |||
524 | void TEWidget::resizeEvent(QResizeEvent* ev) | ||
525 | { | ||
526 | //printf("resize: %d,%d\n",ev->size().width(),ev->size().height()); | ||
527 | //printf("approx: %d,%d\n",ev->size().width()/font_w,ev->size().height()/font_h); | ||
528 | //printf("leaves: %d,%d\n",ev->size().width()%font_w,ev->size().height()%font_h); | ||
529 | //printf("curren: %d,%d\n",width(),height()); | ||
530 | HCNT("resizeEvent"); | ||
531 | |||
532 | // see comment in `paintEvent' concerning the rounding. | ||
533 | //FIXME: could make a routine here; check width(),height() | ||
534 | assert(ev->size().width() == width()); | ||
535 | assert(ev->size().height() == height()); | ||
536 | |||
537 | propagateSize(); | ||
538 | } | ||
539 | |||
540 | void TEWidget::propagateSize() | ||
541 | { | ||
542 | ca* oldimg = image; | ||
543 | int oldlin = lines; | ||
544 | int oldcol = columns; | ||
545 | makeImage(); | ||
546 | // we copy the old image to reduce flicker | ||
547 | int lins = QMIN(oldlin,lines); | ||
548 | int cols = QMIN(oldcol,columns); | ||
549 | if (oldimg) | ||
550 | { | ||
551 | for (int lin = 0; lin < lins; lin++) | ||
552 | memcpy((void*)&image[columns*lin], | ||
553 | (void*)&oldimg[oldcol*lin],cols*sizeof(ca)); | ||
554 | free(oldimg); //FIXME: try new,delete | ||
555 | } | ||
556 | else | ||
557 | clearImage(); | ||
558 | |||
559 | //NOTE: control flows from the back through the chest right into the eye. | ||
560 | // `emu' will call back via `setImage'. | ||
561 | |||
562 | resizing = TRUE; | ||
563 | emit changedImageSizeSignal(lines, columns); // expose resizeEvent | ||
564 | resizing = FALSE; | ||
565 | } | ||
566 | |||
567 | /* ------------------------------------------------------------------------- */ | ||
568 | /* */ | ||
569 | /* Scrollbar */ | ||
570 | /* */ | ||
571 | /* ------------------------------------------------------------------------- */ | ||
572 | |||
573 | void TEWidget::scrollChanged(int) | ||
574 | { | ||
575 | emit changedHistoryCursor(scrollbar->value()); //expose | ||
576 | } | ||
577 | |||
578 | void TEWidget::setScroll(int cursor, int slines) | ||
579 | { | ||
580 | disconnect(scrollbar, SIGNAL(valueChanged(int)), this, SLOT(scrollChanged(int))); | ||
581 | scrollbar->setRange(0,slines); | ||
582 | scrollbar->setSteps(1,lines); | ||
583 | scrollbar->setValue(cursor); | ||
584 | connect(scrollbar, SIGNAL(valueChanged(int)), this, SLOT(scrollChanged(int))); | ||
585 | } | ||
586 | |||
587 | void TEWidget::setScrollbarLocation(int loc) | ||
588 | { | ||
589 | if (scrollLoc == loc) return; // quickly | ||
590 | scrollLoc = loc; | ||
591 | propagateSize(); | ||
592 | update(); | ||
593 | } | ||
594 | |||
595 | /* ------------------------------------------------------------------------- */ | ||
596 | /* */ | ||
597 | /* Mouse */ | ||
598 | /* */ | ||
599 | /* ------------------------------------------------------------------------- */ | ||
600 | |||
601 | /*! | ||
602 | Three different operations can be performed using the mouse, and the | ||
603 | routines in this section serve all of them: | ||
604 | |||
605 | 1) The press/release events are exposed to the application | ||
606 | 2) Marking (press and move left button) and Pasting (press middle button) | ||
607 | 3) The right mouse button is used from the configuration menu | ||
608 | |||
609 | NOTE: During the marking process we attempt to keep the cursor within | ||
610 | the bounds of the text as being displayed by setting the mouse position | ||
611 | whenever the mouse has left the text area. | ||
612 | |||
613 | Two reasons to do so: | ||
614 | 1) QT does not allow the `grabMouse' to confine-to the TEWidget. | ||
615 | Thus a `XGrapPointer' would have to be used instead. | ||
616 | 2) Even if so, this would not help too much, since the text area | ||
617 | of the TEWidget is normally not identical with it's bounds. | ||
618 | |||
619 | The disadvantage of the current handling is, that the mouse can visibly | ||
620 | leave the bounds of the widget and is then moved back. Because of the | ||
621 | current construction, and the reasons mentioned above, we cannot do better | ||
622 | without changing the overall construction. | ||
623 | */ | ||
624 | |||
625 | /*! | ||
626 | */ | ||
627 | |||
628 | void TEWidget::mousePressEvent(QMouseEvent* ev) | ||
629 | { | ||
630 | //printf("press [%d,%d] %d\n",ev->x()/font_w,ev->y()/font_h,ev->button()); | ||
631 | if ( !contentsRect().contains(ev->pos()) ) return; | ||
632 | QPoint tL = contentsRect().topLeft(); | ||
633 | int tLx = tL.x(); | ||
634 | int tLy = tL.y(); | ||
635 | |||
636 | word_selection_mode = FALSE; | ||
637 | |||
638 | //printf("press top left [%d,%d] by=%d\n",tLx,tLy, bY); | ||
639 | if ( ev->button() == LeftButton) | ||
640 | { | ||
641 | QPoint pos = QPoint((ev->x()-tLx-blX)/font_w,(ev->y()-tLy-bY)/font_h); | ||
642 | |||
643 | if ( ev->state() & ControlButton ) preserve_line_breaks = FALSE ; | ||
644 | |||
645 | if (mouse_marks || (ev->state() & ShiftButton)) | ||
646 | { | ||
647 | emit clearSelectionSignal(); | ||
648 | iPntSel = pntSel = pos; | ||
649 | actSel = 1; // left mouse button pressed but nothing selected yet. | ||
650 | grabMouse( /*crossCursor*/ ); // handle with care! | ||
651 | } | ||
652 | else | ||
653 | { | ||
654 | emit mouseSignal( 0, pos.x() + 1, pos.y() + 1 ); // left button | ||
655 | } | ||
656 | } | ||
657 | if ( ev->button() == MidButton ) | ||
658 | { | ||
659 | emitSelection(); | ||
660 | } | ||
661 | if ( ev->button() == RightButton ) // Configure | ||
662 | { | ||
663 | emit configureRequest( this, ev->state()&(ShiftButton|ControlButton), ev->x(), ev->y() ); | ||
664 | } | ||
665 | } | ||
666 | |||
667 | void TEWidget::mouseMoveEvent(QMouseEvent* ev) | ||
668 | { | ||
669 | // for auto-hiding the cursor, we need mouseTracking | ||
670 | if (ev->state() == NoButton ) return; | ||
671 | |||
672 | if (actSel == 0) return; | ||
673 | |||
674 | // don't extend selection while pasting | ||
675 | if (ev->state() & MidButton) return; | ||
676 | |||
677 | //if ( !contentsRect().contains(ev->pos()) ) return; | ||
678 | QPoint tL = contentsRect().topLeft(); | ||
679 | int tLx = tL.x(); | ||
680 | int tLy = tL.y(); | ||
681 | int scroll = scrollbar->value(); | ||
682 | |||
683 | // we're in the process of moving the mouse with the left button pressed | ||
684 | // the mouse cursor will kept catched within the bounds of the text in | ||
685 | // this widget. | ||
686 | |||
687 | // Adjust position within text area bounds. See FIXME above. | ||
688 | QPoint pos = ev->pos(); | ||
689 | if ( pos.x() < tLx+blX ) pos.setX( tLx+blX ); | ||
690 | if ( pos.x() > tLx+blX+columns*font_w-1 ) pos.setX( tLx+blX+columns*font_w ); | ||
691 | if ( pos.y() < tLy+bY ) pos.setY( tLy+bY ); | ||
692 | if ( pos.y() > tLy+bY+lines*font_h-1 ) pos.setY( tLy+bY+lines*font_h-1 ); | ||
693 | // check if we produce a mouse move event by this | ||
694 | if ( pos != ev->pos() ) cursor().setPos(mapToGlobal(pos)); | ||
695 | |||
696 | if ( pos.y() == tLy+bY+lines*font_h-1 ) | ||
697 | { | ||
698 | scrollbar->setValue(scrollbar->value()+yMouseScroll); // scrollforward | ||
699 | } | ||
700 | if ( pos.y() == tLy+bY ) | ||
701 | { | ||
702 | scrollbar->setValue(scrollbar->value()-yMouseScroll); // scrollback | ||
703 | } | ||
704 | |||
705 | QPoint here = QPoint((pos.x()-tLx-blX)/font_w,(pos.y()-tLy-bY)/font_h); | ||
706 | QPoint ohere; | ||
707 | bool swapping = FALSE; | ||
708 | |||
709 | if ( word_selection_mode ) | ||
710 | { | ||
711 | // Extend to word boundaries | ||
712 | int i; | ||
713 | int selClass; | ||
714 | |||
715 | bool left_not_right = ( here.y() < iPntSel.y() || | ||
716 | here.y() == iPntSel.y() && here.x() < iPntSel.x() ); | ||
717 | bool old_left_not_right = ( pntSel.y() < iPntSel.y() || | ||
718 | pntSel.y() == iPntSel.y() && pntSel.x() < iPntSel.x() ); | ||
719 | swapping = left_not_right != old_left_not_right; | ||
720 | |||
721 | // Find left (left_not_right ? from here : from start) | ||
722 | QPoint left = left_not_right ? here : iPntSel; | ||
723 | i = loc(left.x(),left.y()); | ||
724 | selClass = charClass(image[i].c); | ||
725 | while ( left.x() > 0 && charClass(image[i-1].c) == selClass ) | ||
726 | { i--; left.rx()--; } | ||
727 | |||
728 | // Find left (left_not_right ? from start : from here) | ||
729 | QPoint right = left_not_right ? iPntSel : here; | ||
730 | i = loc(right.x(),right.y()); | ||
731 | selClass = charClass(image[i].c); | ||
732 | while ( right.x() < columns-1 && charClass(image[i+1].c) == selClass ) | ||
733 | { i++; right.rx()++; } | ||
734 | |||
735 | // Pick which is start (ohere) and which is extension (here) | ||
736 | if ( left_not_right ) | ||
737 | { | ||
738 | here = left; ohere = right; | ||
739 | } | ||
740 | else | ||
741 | { | ||
742 | here = right; ohere = left; | ||
743 | } | ||
744 | } | ||
745 | |||
746 | if (here == pntSel && scroll == scrollbar->value()) return; // not moved | ||
747 | |||
748 | if ( word_selection_mode ) { | ||
749 | if ( actSel < 2 || swapping ) { | ||
750 | emit beginSelectionSignal( ohere.x(), ohere.y() ); | ||
751 | } | ||
752 | } else if ( actSel < 2 ) { | ||
753 | emit beginSelectionSignal( pntSel.x(), pntSel.y() ); | ||
754 | } | ||
755 | |||
756 | actSel = 2; // within selection | ||
757 | pntSel = here; | ||
758 | emit extendSelectionSignal( here.x(), here.y() ); | ||
759 | } | ||
760 | |||
761 | void TEWidget::mouseReleaseEvent(QMouseEvent* ev) | ||
762 | { | ||
763 | //printf("release [%d,%d] %d\n",ev->x()/font_w,ev->y()/font_h,ev->button()); | ||
764 | if ( ev->button() == LeftButton) | ||
765 | { | ||
766 | if ( actSel > 1 ) emit endSelectionSignal(preserve_line_breaks); | ||
767 | preserve_line_breaks = TRUE; | ||
768 | actSel = 0; | ||
769 | |||
770 | //FIXME: emits a release event even if the mouse is | ||
771 | // outside the range. The procedure used in `mouseMoveEvent' | ||
772 | // applies here, too. | ||
773 | |||
774 | QPoint tL = contentsRect().topLeft(); | ||
775 | int tLx = tL.x(); | ||
776 | int tLy = tL.y(); | ||
777 | |||
778 | if (!mouse_marks && !(ev->state() & ShiftButton)) | ||
779 | emit mouseSignal( 3, // release | ||
780 | (ev->x()-tLx-blX)/font_w + 1, | ||
781 | (ev->y()-tLy-bY)/font_h + 1 ); | ||
782 | releaseMouse(); | ||
783 | } | ||
784 | } | ||
785 | |||
786 | void TEWidget::mouseDoubleClickEvent(QMouseEvent* ev) | ||
787 | { | ||
788 | if ( ev->button() != LeftButton) return; | ||
789 | |||
790 | QPoint tL = contentsRect().topLeft(); | ||
791 | int tLx = tL.x(); | ||
792 | int tLy = tL.y(); | ||
793 | QPoint pos = QPoint((ev->x()-tLx-blX)/font_w,(ev->y()-tLy-bY)/font_h); | ||
794 | |||
795 | // pass on double click as two clicks. | ||
796 | if (!mouse_marks && !(ev->state() & ShiftButton)) | ||
797 | { | ||
798 | emit mouseSignal( 0, pos.x()+1, pos.y()+1 ); // left button | ||
799 | emit mouseSignal( 3, pos.x()+1, pos.y()+1 ); // release | ||
800 | emit mouseSignal( 0, pos.x()+1, pos.y()+1 ); // left button | ||
801 | return; | ||
802 | } | ||
803 | |||
804 | |||
805 | emit clearSelectionSignal(); | ||
806 | QPoint bgnSel = pos; | ||
807 | QPoint endSel = QPoint((ev->x()-tLx-blX)/font_w,(ev->y()-tLy-bY)/font_h); | ||
808 | int i = loc(bgnSel.x(),bgnSel.y()); | ||
809 | iPntSel = bgnSel; | ||
810 | |||
811 | word_selection_mode = TRUE; | ||
812 | |||
813 | // find word boundaries... | ||
814 | int selClass = charClass(image[i].c); | ||
815 | { | ||
816 | // set the start... | ||
817 | int x = bgnSel.x(); | ||
818 | while ( x > 0 && charClass(image[i-1].c) == selClass ) | ||
819 | { i--; x--; } | ||
820 | bgnSel.setX(x); | ||
821 | emit beginSelectionSignal( bgnSel.x(), bgnSel.y() ); | ||
822 | |||
823 | // set the end... | ||
824 | i = loc( endSel.x(), endSel.y() ); | ||
825 | x = endSel.x(); | ||
826 | while( x < columns-1 && charClass(image[i+1].c) == selClass ) | ||
827 | { i++; x++ ; } | ||
828 | endSel.setX(x); | ||
829 | actSel = 2; // within selection | ||
830 | emit extendSelectionSignal( endSel.x(), endSel.y() ); | ||
831 | emit endSelectionSignal(preserve_line_breaks); | ||
832 | preserve_line_breaks = TRUE; | ||
833 | } | ||
834 | } | ||
835 | |||
836 | void TEWidget::focusInEvent( QFocusEvent * ) | ||
837 | { | ||
838 | // do nothing, to prevent repainting | ||
839 | } | ||
840 | |||
841 | |||
842 | void TEWidget::focusOutEvent( QFocusEvent * ) | ||
843 | { | ||
844 | // do nothing, to prevent repainting | ||
845 | } | ||
846 | |||
847 | bool TEWidget::focusNextPrevChild( bool next ) | ||
848 | { | ||
849 | if (next) | ||
850 | return false; // This disables changing the active part in konqueror | ||
851 | // when pressing Tab | ||
852 | return QFrame::focusNextPrevChild( next ); | ||
853 | } | ||
854 | |||
855 | |||
856 | int TEWidget::charClass(char ch) const | ||
857 | { | ||
858 | // This might seem like overkill, but imagine if ch was a Unicode | ||
859 | // character (Qt 2.0 QChar) - it might then be sensible to separate | ||
860 | // the different language ranges, etc. | ||
861 | |||
862 | if ( isspace(ch) ) return ' '; | ||
863 | |||
864 | static const char *word_characters = ":@-./_~"; | ||
865 | if ( isalnum(ch) || strchr(word_characters, ch) ) | ||
866 | return 'a'; | ||
867 | |||
868 | // Everything else is weird | ||
869 | return 1; | ||
870 | } | ||
871 | |||
872 | void TEWidget::setMouseMarks(bool on) | ||
873 | { | ||
874 | mouse_marks = on; | ||
875 | setCursor( mouse_marks ? ibeamCursor : arrowCursor ); | ||
876 | } | ||
877 | |||
878 | /* ------------------------------------------------------------------------- */ | ||
879 | /* */ | ||
880 | /* Clipboard */ | ||
881 | /* */ | ||
882 | /* ------------------------------------------------------------------------- */ | ||
883 | |||
884 | #undef KeyPress | ||
885 | |||
886 | void TEWidget::emitSelection() | ||
887 | // Paste Clipboard by simulating keypress events | ||
888 | { | ||
889 | #ifndef QT_NO_CLIPBOARD | ||
890 | QString text = QApplication::clipboard()->text(); | ||
891 | if ( ! text.isNull() ) | ||
892 | { | ||
893 | text.replace(QRegExp("\n"), "\r"); | ||
894 | QKeyEvent e(QEvent::KeyPress, 0, -1, 0, text); | ||
895 | emit keyPressedSignal(&e); // expose as a big fat keypress event | ||
896 | emit clearSelectionSignal(); | ||
897 | } | ||
898 | #endif | ||
899 | } | ||
900 | |||
901 | void TEWidget::emitText(QString text) | ||
902 | { | ||
903 | QKeyEvent e(QEvent::KeyPress, 0, -1, 0, text); | ||
904 | emit keyPressedSignal(&e); // expose as a big fat keypress event | ||
905 | } | ||
906 | |||
907 | void TEWidget::pasteClipboard( ) | ||
908 | { | ||
909 | emitSelection(); | ||
910 | } | ||
911 | |||
912 | void TEWidget::setSelection(const QString& t) | ||
913 | { | ||
914 | #ifndef QT_NO_CLIPBOARD | ||
915 | // Disconnect signal while WE set the clipboard | ||
916 | QObject *cb = QApplication::clipboard(); | ||
917 | QObject::disconnect( cb, SIGNAL(dataChanged()), | ||
918 | this, SLOT(onClearSelection()) ); | ||
919 | |||
920 | QApplication::clipboard()->setText(t); | ||
921 | |||
922 | QObject::connect( cb, SIGNAL(dataChanged()), | ||
923 | this, SLOT(onClearSelection()) ); | ||
924 | #endif | ||
925 | } | ||
926 | |||
927 | void TEWidget::onClearSelection() | ||
928 | { | ||
929 | emit clearSelectionSignal(); | ||
930 | } | ||
931 | |||
932 | /* ------------------------------------------------------------------------- */ | ||
933 | /* */ | ||
934 | /* Keyboard */ | ||
935 | /* */ | ||
936 | /* ------------------------------------------------------------------------- */ | ||
937 | |||
938 | //FIXME: an `eventFilter' has been installed instead of a `keyPressEvent' | ||
939 | // due to a bug in `QT' or the ignorance of the author to prevent | ||
940 | // repaint events being emitted to the screen whenever one leaves | ||
941 | // or reenters the screen to/from another application. | ||
942 | // | ||
943 | // Troll says one needs to change focusInEvent() and focusOutEvent(), | ||
944 | // which would also let you have an in-focus cursor and an out-focus | ||
945 | // cursor like xterm does. | ||
946 | |||
947 | // for the auto-hide cursor feature, I added empty focusInEvent() and | ||
948 | // focusOutEvent() so that update() isn't called. | ||
949 | // For auto-hide, we need to get keypress-events, but we only get them when | ||
950 | // we have focus. | ||
951 | |||
952 | void TEWidget::doScroll(int lines) | ||
953 | { | ||
954 | scrollbar->setValue(scrollbar->value()+lines); | ||
955 | } | ||
956 | |||
957 | bool TEWidget::eventFilter( QObject *obj, QEvent *e ) | ||
958 | { | ||
959 | if ( (e->type() == QEvent::Accel || | ||
960 | e->type() == QEvent::AccelAvailable ) && qApp->focusWidget() == this ) | ||
961 | { | ||
962 | static_cast<QKeyEvent *>( e )->ignore(); | ||
963 | return true; | ||
964 | } | ||
965 | if ( obj != this /* when embedded */ && obj != parent() /* when standalone */ ) | ||
966 | return FALSE; // not us | ||
967 | if ( e->type() == QEvent::Wheel) | ||
968 | { | ||
969 | QApplication::sendEvent(scrollbar, e); | ||
970 | } | ||
971 | |||
972 | #ifdef FAKE_CTRL_AND_ALT | ||
973 | static bool control = FALSE; | ||
974 | static bool alt = FALSE; | ||
975 | // Has a keyboard with no CTRL and ALT keys, but we fake it: | ||
976 | bool dele=FALSE; | ||
977 | if ( e->type() == QEvent::KeyPress || e->type() == QEvent::KeyRelease ) { | ||
978 | QKeyEvent* ke = (QKeyEvent*)e; | ||
979 | bool keydown = e->type() == QEvent::KeyPress || ke->isAutoRepeat(); | ||
980 | switch (ke->key()) { | ||
981 | case Key_F9: // let this be "Control" | ||
982 | control = keydown; | ||
983 | e = new QKeyEvent(QEvent::KeyPress, Key_Control, 0, ke->state()); | ||
984 | dele=TRUE; | ||
985 | break; | ||
986 | case Key_F13: // let this be "Alt" | ||
987 | alt = keydown; | ||
988 | e = new QKeyEvent(QEvent::KeyPress, Key_Alt, 0, ke->state()); | ||
989 | dele=TRUE; | ||
990 | break; | ||
991 | default: | ||
992 | if ( control ) { | ||
993 | int a = toupper(ke->ascii())-64; | ||
994 | if ( a >= 0 && a < ' ' ) { | ||
995 | e = new QKeyEvent(e->type(), ke->key(), | ||
996 | a, ke->state()|ControlButton, QChar(a,0)); | ||
997 | dele=TRUE; | ||
998 | } | ||
999 | } | ||
1000 | if ( alt ) { | ||
1001 | e = new QKeyEvent(e->type(), ke->key(), | ||
1002 | ke->ascii(), ke->state()|AltButton, ke->text()); | ||
1003 | dele=TRUE; | ||
1004 | } | ||
1005 | } | ||
1006 | } | ||
1007 | #endif | ||
1008 | |||
1009 | if ( e->type() == QEvent::KeyPress ) | ||
1010 | { | ||
1011 | QKeyEvent* ke = (QKeyEvent*)e; | ||
1012 | |||
1013 | actSel=0; // Key stroke implies a screen update, so TEWidget won't | ||
1014 | // know where the current selection is. | ||
1015 | |||
1016 | emit keyPressedSignal(ke); // expose | ||
1017 | ke->accept(); | ||
1018 | #ifdef FAKE_CTRL_AND_ALT | ||
1019 | if ( dele ) delete e; | ||
1020 | #endif | ||
1021 | return true; // stop the event | ||
1022 | } | ||
1023 | if ( e->type() == QEvent::Enter ) | ||
1024 | { | ||
1025 | QObject::disconnect( (QObject*)cb, SIGNAL(dataChanged()), | ||
1026 | this, SLOT(onClearSelection()) ); | ||
1027 | } | ||
1028 | if ( e->type() == QEvent::Leave ) | ||
1029 | { | ||
1030 | QObject::connect( (QObject*)cb, SIGNAL(dataChanged()), | ||
1031 | this, SLOT(onClearSelection()) ); | ||
1032 | } | ||
1033 | return QFrame::eventFilter( obj, e ); | ||
1034 | } | ||
1035 | |||
1036 | /* ------------------------------------------------------------------------- */ | ||
1037 | /* */ | ||
1038 | /* Frame */ | ||
1039 | /* */ | ||
1040 | /* ------------------------------------------------------------------------- */ | ||
1041 | |||
1042 | void TEWidget::frameChanged() | ||
1043 | { | ||
1044 | propagateSize(); | ||
1045 | update(); | ||
1046 | } | ||
1047 | |||
1048 | /* ------------------------------------------------------------------------- */ | ||
1049 | /* */ | ||
1050 | /* Sound */ | ||
1051 | /* */ | ||
1052 | /* ------------------------------------------------------------------------- */ | ||
1053 | |||
1054 | void TEWidget::Bell() | ||
1055 | { | ||
1056 | QApplication::beep(); | ||
1057 | } | ||
1058 | |||
1059 | /* ------------------------------------------------------------------------- */ | ||
1060 | /* */ | ||
1061 | /* Auxiluary */ | ||
1062 | /* */ | ||
1063 | /* ------------------------------------------------------------------------- */ | ||
1064 | |||
1065 | void TEWidget::clearImage() | ||
1066 | // initialize the image | ||
1067 | // for internal use only | ||
1068 | { | ||
1069 | for (int y = 0; y < lines; y++) | ||
1070 | for (int x = 0; x < columns; x++) | ||
1071 | { | ||
1072 | image[loc(x,y)].c = 0xff; //' '; | ||
1073 | image[loc(x,y)].f = 0xff; //DEFAULT_FORE_COLOR; | ||
1074 | image[loc(x,y)].b = 0xff; //DEFAULT_BACK_COLOR; | ||
1075 | image[loc(x,y)].r = 0xff; //DEFAULT_RENDITION; | ||
1076 | } | ||
1077 | } | ||
1078 | |||
1079 | // Create Image /////////////////////////////////////////////////////// | ||
1080 | |||
1081 | void TEWidget::calcGeometry() | ||
1082 | { | ||
1083 | //FIXME: set rimX == rimY == 0 when running in full screen mode. | ||
1084 | |||
1085 | scrollbar->resize(QApplication::style().scrollBarExtent().width(), | ||
1086 | contentsRect().height()); | ||
1087 | switch(scrollLoc) | ||
1088 | { | ||
1089 | case SCRNONE : | ||
1090 | columns = ( contentsRect().width() - 2 * rimX ) / font_w; | ||
1091 | blX = (contentsRect().width() - (columns*font_w) ) / 2; | ||
1092 | brX = blX; | ||
1093 | scrollbar->hide(); | ||
1094 | break; | ||
1095 | case SCRLEFT : | ||
1096 | columns = ( contentsRect().width() - 2 * rimX - scrollbar->width()) / font_w; | ||
1097 | brX = (contentsRect().width() - (columns*font_w) - scrollbar->width() ) / 2; | ||
1098 | blX = brX + scrollbar->width(); | ||
1099 | scrollbar->move(contentsRect().topLeft()); | ||
1100 | scrollbar->show(); | ||
1101 | break; | ||
1102 | case SCRRIGHT: | ||
1103 | columns = ( contentsRect().width() - 2 * rimX - scrollbar->width()) / font_w; | ||
1104 | blX = (contentsRect().width() - (columns*font_w) - scrollbar->width() ) / 2; | ||
1105 | brX = blX; | ||
1106 | scrollbar->move(contentsRect().topRight() - QPoint(scrollbar->width()-1,0)); | ||
1107 | scrollbar->show(); | ||
1108 | break; | ||
1109 | } | ||
1110 | //FIXME: support 'rounding' styles | ||
1111 | lines = ( contentsRect().height() - 2 * rimY ) / font_h; | ||
1112 | bY = (contentsRect().height() - (lines *font_h)) / 2; | ||
1113 | } | ||
1114 | |||
1115 | void TEWidget::makeImage() | ||
1116 | //FIXME: rename 'calcGeometry? | ||
1117 | { | ||
1118 | calcGeometry(); | ||
1119 | image = (ca*) malloc(lines*columns*sizeof(ca)); | ||
1120 | clearImage(); | ||
1121 | } | ||
1122 | |||
1123 | // calculate the needed size | ||
1124 | QSize TEWidget::calcSize(int cols, int lins) const | ||
1125 | { | ||
1126 | int frw = width() - contentsRect().width(); | ||
1127 | int frh = height() - contentsRect().height(); | ||
1128 | int scw = (scrollLoc==SCRNONE?0:scrollbar->width()); | ||
1129 | return QSize( font_w*cols + 2*rimX + frw + scw, font_h*lins + 2*rimY + frh ); | ||
1130 | } | ||
1131 | |||
1132 | QSize TEWidget::sizeHint() const | ||
1133 | { | ||
1134 | return size(); | ||
1135 | } | ||
1136 | |||
1137 | void TEWidget::styleChange(QStyle &) | ||
1138 | { | ||
1139 | propagateSize(); | ||
1140 | } | ||
1141 | |||
1142 | #ifndef QT_NO_DRAGANDDROP | ||
1143 | |||
1144 | /* --------------------------------------------------------------------- */ | ||
1145 | /* */ | ||
1146 | /* Drag & Drop */ | ||
1147 | /* */ | ||
1148 | /* --------------------------------------------------------------------- */ | ||
1149 | |||
1150 | |||
1151 | void TEWidget::dragEnterEvent(QDragEnterEvent* e) | ||
1152 | { | ||
1153 | e->accept(QTextDrag::canDecode(e) || | ||
1154 | QUriDrag::canDecode(e)); | ||
1155 | } | ||
1156 | |||
1157 | void TEWidget::dropEvent(QDropEvent* event) | ||
1158 | { | ||
1159 | // The current behaviour when url(s) are dropped is | ||
1160 | // * if there is only ONE url and if it's a LOCAL one, ask for paste or cd | ||
1161 | // * in all other cases, just paste | ||
1162 | // (for non-local ones, or for a list of URLs, 'cd' is nonsense) | ||
1163 | QStrList strlist; | ||
1164 | int file_count = 0; | ||
1165 | dropText = ""; | ||
1166 | bool bPopup = true; | ||
1167 | |||
1168 | if(QUriDrag::decode(event, strlist)) { | ||
1169 | if (strlist.count()) { | ||
1170 | for(const char* p = strlist.first(); p; p = strlist.next()) { | ||
1171 | if(file_count++ > 0) { | ||
1172 | dropText += " "; | ||
1173 | bPopup = false; // more than one file, don't popup | ||
1174 | } | ||
1175 | |||
1176 | /* | ||
1177 | KURL url(p); | ||
1178 | if (url.isLocalFile()) { | ||
1179 | dropText += url.path(); // local URL : remove protocol | ||
1180 | } | ||
1181 | else { | ||
1182 | dropText += url.prettyURL(); | ||
1183 | bPopup = false; // a non-local file, don't popup | ||
1184 | } | ||
1185 | */ | ||
1186 | |||
1187 | } | ||
1188 | |||
1189 | if (bPopup) | ||
1190 | // m_drop->popup(pos() + event->pos()); | ||
1191 | m_drop->popup(mapToGlobal(event->pos())); | ||
1192 | else | ||
1193 | { | ||
1194 | if (currentSession) { | ||
1195 | currentSession->getEmulation()->sendString(dropText.local8Bit()); | ||
1196 | } | ||
1197 | // kdDebug() << "Drop:" << dropText.local8Bit() << "\n"; | ||
1198 | } | ||
1199 | } | ||
1200 | } | ||
1201 | else if(QTextDrag::decode(event, dropText)) { | ||
1202 | // kdDebug() << "Drop:" << dropText.local8Bit() << "\n"; | ||
1203 | if (currentSession) { | ||
1204 | currentSession->getEmulation()->sendString(dropText.local8Bit()); | ||
1205 | } | ||
1206 | // Paste it | ||
1207 | } | ||
1208 | } | ||
1209 | #endif | ||
1210 | |||
1211 | |||
1212 | void TEWidget::drop_menu_activated(int item) | ||
1213 | { | ||
1214 | #ifndef QT_NO_DRAGANDDROP | ||
1215 | switch (item) | ||
1216 | { | ||
1217 | case 0: // paste | ||
1218 | currentSession->getEmulation()->sendString(dropText.local8Bit()); | ||
1219 | // KWM::activate((Window)this->winId()); | ||
1220 | break; | ||
1221 | case 1: // cd ... | ||
1222 | currentSession->getEmulation()->sendString("cd "); | ||
1223 | struct stat statbuf; | ||
1224 | if ( ::stat( QFile::encodeName( dropText ), &statbuf ) == 0 ) | ||
1225 | { | ||
1226 | if ( !S_ISDIR(statbuf.st_mode) ) | ||
1227 | { | ||
1228 | /* | ||
1229 | KURL url; | ||
1230 | url.setPath( dropText ); | ||
1231 | dropText = url.directory( true, false ); // remove filename | ||
1232 | */ | ||
1233 | } | ||
1234 | } | ||
1235 | dropText.replace(QRegExp(" "), "\\ "); // escape spaces | ||
1236 | currentSession->getEmulation()->sendString(dropText.local8Bit()); | ||
1237 | currentSession->getEmulation()->sendString("\n"); | ||
1238 | // KWM::activate((Window)this->winId()); | ||
1239 | break; | ||
1240 | } | ||
1241 | #endif | ||
1242 | } | ||
1243 | |||
diff --git a/core/apps/embeddedkonsole/TEWidget.h b/core/apps/embeddedkonsole/TEWidget.h new file mode 100644 index 0000000..3f9f4ae --- a/dev/null +++ b/core/apps/embeddedkonsole/TEWidget.h | |||
@@ -0,0 +1,202 @@ | |||
1 | /* ----------------------------------------------------------------------- */ | ||
2 | /* */ | ||
3 | /* [te_widget.h] Terminal Emulation Widget */ | ||
4 | /* */ | ||
5 | /* ----------------------------------------------------------------------- */ | ||
6 | /* */ | ||
7 | /* Copyright (c) 1997,1998 by Lars Doelle <lars.doelle@on-line.de> */ | ||
8 | /* */ | ||
9 | /* This file is part of Konsole - an X terminal for KDE */ | ||
10 | /* */ | ||
11 | /* ----------------------------------------------------------------------- */ | ||
12 | /* */ | ||
13 | /* Ported Konsole to Qt/Embedded */ | ||
14 | /* */ | ||
15 | /* Copyright (C) 2000 by John Ryland <jryland@trolltech.com> */ | ||
16 | /* */ | ||
17 | /* -------------------------------------------------------------------------- */ | ||
18 | |||
19 | #ifndef TE_WIDGET_H | ||
20 | #define TE_WIDGET_H | ||
21 | |||
22 | #include <qwidget.h> | ||
23 | #include <qlabel.h> | ||
24 | #include <qtimer.h> | ||
25 | #include <qcolor.h> | ||
26 | #include <qkeycode.h> | ||
27 | #include <qscrollbar.h> | ||
28 | |||
29 | #include <qpopupmenu.h> | ||
30 | |||
31 | #include "TECommon.h" | ||
32 | |||
33 | extern unsigned short vt100_graphics[32]; | ||
34 | |||
35 | class TESession; | ||
36 | |||
37 | // class Konsole; | ||
38 | |||
39 | class TEWidget : public QFrame | ||
40 | // a widget representing attributed text | ||
41 | { Q_OBJECT | ||
42 | |||
43 | // friend class Konsole; | ||
44 | |||
45 | public: | ||
46 | |||
47 | TEWidget(QWidget *parent=0, const char *name=0); | ||
48 | virtual ~TEWidget(); | ||
49 | |||
50 | public: | ||
51 | |||
52 | QColor getDefaultBackColor(); | ||
53 | |||
54 | const ColorEntry* getColorTable() const; | ||
55 | void setColorTable(const ColorEntry table[]); | ||
56 | |||
57 | void setScrollbarLocation(int loc); | ||
58 | enum { SCRNONE=0, SCRLEFT=1, SCRRIGHT=2 }; | ||
59 | |||
60 | void setScroll(int cursor, int lines); | ||
61 | void doScroll(int lines); | ||
62 | |||
63 | void emitSelection(); | ||
64 | |||
65 | public: | ||
66 | |||
67 | void setImage(const ca* const newimg, int lines, int columns); | ||
68 | |||
69 | int Lines() { return lines; } | ||
70 | int Columns() { return columns; } | ||
71 | |||
72 | void calcGeometry(); | ||
73 | void propagateSize(); | ||
74 | QSize calcSize(int cols, int lins) const; | ||
75 | |||
76 | QSize sizeHint() const; | ||
77 | |||
78 | public: | ||
79 | |||
80 | void Bell(); | ||
81 | void emitText(QString text); | ||
82 | void pasteClipboard(); | ||
83 | |||
84 | signals: | ||
85 | |||
86 | void keyPressedSignal(QKeyEvent *e); | ||
87 | void mouseSignal(int cb, int cx, int cy); | ||
88 | void changedImageSizeSignal(int lines, int columns); | ||
89 | void changedHistoryCursor(int value); | ||
90 | void configureRequest( TEWidget*, int state, int x, int y ); | ||
91 | |||
92 | void clearSelectionSignal(); | ||
93 | void beginSelectionSignal( const int x, const int y ); | ||
94 | void extendSelectionSignal( const int x, const int y ); | ||
95 | void endSelectionSignal(const BOOL preserve_line_breaks); | ||
96 | |||
97 | |||
98 | protected: | ||
99 | |||
100 | virtual void styleChange( QStyle& ); | ||
101 | |||
102 | bool eventFilter( QObject *, QEvent * ); | ||
103 | |||
104 | void drawAttrStr(QPainter &paint, QRect rect, | ||
105 | QString& str, ca attr, BOOL pm, BOOL clear); | ||
106 | void paintEvent( QPaintEvent * ); | ||
107 | |||
108 | void resizeEvent(QResizeEvent*); | ||
109 | |||
110 | void fontChange(const QFont &font); | ||
111 | void frameChanged(); | ||
112 | |||
113 | void mouseDoubleClickEvent(QMouseEvent* ev); | ||
114 | void mousePressEvent( QMouseEvent* ); | ||
115 | void mouseReleaseEvent( QMouseEvent* ); | ||
116 | void mouseMoveEvent( QMouseEvent* ); | ||
117 | |||
118 | void focusInEvent( QFocusEvent * ); | ||
119 | void focusOutEvent( QFocusEvent * ); | ||
120 | bool focusNextPrevChild( bool next ); | ||
121 | |||
122 | #ifndef QT_NO_DRAGANDDROP | ||
123 | // Dnd | ||
124 | void dragEnterEvent(QDragEnterEvent* event); | ||
125 | void dropEvent(QDropEvent* event); | ||
126 | #endif | ||
127 | |||
128 | virtual int charClass(char) const; | ||
129 | |||
130 | void clearImage(); | ||
131 | |||
132 | public: | ||
133 | const QPixmap *backgroundPixmap(); | ||
134 | |||
135 | void setSelection(const QString &t); | ||
136 | |||
137 | virtual void setFont(const QFont &); | ||
138 | void setVTFont(const QFont &); | ||
139 | QFont getVTFont(); | ||
140 | |||
141 | void setMouseMarks(bool on); | ||
142 | |||
143 | public slots: | ||
144 | |||
145 | void onClearSelection(); | ||
146 | |||
147 | protected slots: | ||
148 | |||
149 | void scrollChanged(int value); | ||
150 | void blinkEvent(); | ||
151 | |||
152 | private: | ||
153 | |||
154 | QChar (*fontMap)(QChar); // possible vt100 font extention | ||
155 | |||
156 | bool fixed_font; // has fixed pitch | ||
157 | int font_h; // height | ||
158 | int font_w; // width | ||
159 | int font_a; // ascend | ||
160 | |||
161 | int blX; // actual offset (left) | ||
162 | int brX; // actual offset (right) | ||
163 | int bY; // actual offset | ||
164 | |||
165 | int lines; | ||
166 | int columns; | ||
167 | ca *image; // [lines][columns] | ||
168 | |||
169 | ColorEntry color_table[TABLE_COLORS]; | ||
170 | |||
171 | BOOL resizing; | ||
172 | bool mouse_marks; | ||
173 | |||
174 | void makeImage(); | ||
175 | |||
176 | QPoint iPntSel; // initial selection point | ||
177 | QPoint pntSel; // current selection point | ||
178 | int actSel; // selection state | ||
179 | BOOL word_selection_mode; | ||
180 | BOOL preserve_line_breaks; | ||
181 | |||
182 | QClipboard* cb; | ||
183 | QScrollBar* scrollbar; | ||
184 | int scrollLoc; | ||
185 | |||
186 | //#define SCRNONE 0 | ||
187 | //#define SCRLEFT 1 | ||
188 | //#define SCRRIGHT 2 | ||
189 | |||
190 | BOOL blinking; // hide text in paintEvent | ||
191 | BOOL hasBlinker; // has characters to blink | ||
192 | QTimer* blinkT; // active when hasBlinker | ||
193 | QPopupMenu* m_drop; | ||
194 | QString dropText; | ||
195 | public: | ||
196 | // current session in this widget | ||
197 | TESession *currentSession; | ||
198 | private slots: | ||
199 | void drop_menu_activated(int item); | ||
200 | }; | ||
201 | |||
202 | #endif // TE_WIDGET_H | ||
diff --git a/core/apps/embeddedkonsole/TEmuVt102.cpp b/core/apps/embeddedkonsole/TEmuVt102.cpp new file mode 100644 index 0000000..752c49f --- a/dev/null +++ b/core/apps/embeddedkonsole/TEmuVt102.cpp | |||
@@ -0,0 +1,991 @@ | |||
1 | /* ------------------------------------------------------------------------- */ | ||
2 | /* */ | ||
3 | /* [TEmuVt102.C] VT102 Terminal Emulation */ | ||
4 | /* */ | ||
5 | /* ------------------------------------------------------------------------- */ | ||
6 | /* */ | ||
7 | /* Copyright (c) 1997,1998 by Lars Doelle <lars.doelle@on-line.de> */ | ||
8 | /* */ | ||
9 | /* This file is part of Konsole - an X terminal for KDE */ | ||
10 | /* */ | ||
11 | /* ------------------------------------------------------------------------- */ | ||
12 | /* */ | ||
13 | /* Ported Konsole to Qt/Embedded */ | ||
14 | /* */ | ||
15 | /* Copyright (C) 2000 by John Ryland <jryland@trolltech.com> */ | ||
16 | /* */ | ||
17 | /* -------------------------------------------------------------------------- */ | ||
18 | |||
19 | /*! \class TEmuVt102 | ||
20 | |||
21 | \brief Actual Emulation for Konsole | ||
22 | |||
23 | \sa TEWidget \sa TEScreen | ||
24 | */ | ||
25 | |||
26 | #include "TEmuVt102.h" | ||
27 | #include "TEWidget.h" | ||
28 | #include "TEScreen.h" | ||
29 | #include "keytrans.h" | ||
30 | |||
31 | #include <stdio.h> | ||
32 | #include <unistd.h> | ||
33 | #include <qkeycode.h> | ||
34 | #include <qtextcodec.h> | ||
35 | |||
36 | |||
37 | /* VT102 Terminal Emulation | ||
38 | |||
39 | This class puts together the screens, the pty and the widget to a | ||
40 | complete terminal emulation. Beside combining it's componentes, it | ||
41 | handles the emulations's protocol. | ||
42 | |||
43 | This module consists of the following sections: | ||
44 | |||
45 | - Constructor/Destructor | ||
46 | - Incoming Bytes Event pipeline | ||
47 | - Outgoing Bytes | ||
48 | - Mouse Events | ||
49 | - Keyboard Events | ||
50 | - Modes and Charset State | ||
51 | - Diagnostics | ||
52 | */ | ||
53 | |||
54 | |||
55 | /* ------------------------------------------------------------------------- */ | ||
56 | /* */ | ||
57 | /* Constructor / Destructor */ | ||
58 | /* */ | ||
59 | /* ------------------------------------------------------------------------- */ | ||
60 | |||
61 | /* | ||
62 | Nothing really intesting happens here. | ||
63 | */ | ||
64 | |||
65 | /*! | ||
66 | */ | ||
67 | |||
68 | TEmuVt102::TEmuVt102(TEWidget* gui) : TEmulation(gui) | ||
69 | { | ||
70 | QObject::connect(gui,SIGNAL(mouseSignal(int,int,int)), | ||
71 | this,SLOT(onMouse(int,int,int))); | ||
72 | initTokenizer(); | ||
73 | reset(); | ||
74 | } | ||
75 | |||
76 | /*! | ||
77 | */ | ||
78 | |||
79 | TEmuVt102::~TEmuVt102() | ||
80 | { | ||
81 | } | ||
82 | |||
83 | /*! | ||
84 | */ | ||
85 | |||
86 | void TEmuVt102::reset() | ||
87 | { | ||
88 | resetToken(); | ||
89 | resetModes(); | ||
90 | resetCharset(0); screen[0]->reset(); | ||
91 | resetCharset(1); screen[0]->reset(); | ||
92 | setCodec(0); | ||
93 | setKeytrans("linux.keytab"); | ||
94 | } | ||
95 | |||
96 | /* ------------------------------------------------------------------------- */ | ||
97 | /* */ | ||
98 | /* Processing the incoming byte stream */ | ||
99 | /* */ | ||
100 | /* ------------------------------------------------------------------------- */ | ||
101 | |||
102 | /* Incoming Bytes Event pipeline | ||
103 | |||
104 | This section deals with decoding the incoming character stream. | ||
105 | Decoding means here, that the stream is first seperated into `tokens' | ||
106 | which are then mapped to a `meaning' provided as operations by the | ||
107 | `TEScreen' class or by the emulation class itself. | ||
108 | |||
109 | The pipeline proceeds as follows: | ||
110 | |||
111 | - Tokenizing the ESC codes (onRcvChar) | ||
112 | - VT100 code page translation of plain characters (applyCharset) | ||
113 | - Interpretation of ESC codes (tau) | ||
114 | |||
115 | The escape codes and their meaning are described in the | ||
116 | technical reference of this program. | ||
117 | */ | ||
118 | |||
119 | // Tokens ------------------------------------------------------------------ -- | ||
120 | |||
121 | /* | ||
122 | Since the tokens are the central notion if this section, we've put them | ||
123 | in front. They provide the syntactical elements used to represent the | ||
124 | terminals operations as byte sequences. | ||
125 | |||
126 | They are encodes here into a single machine word, so that we can later | ||
127 | switch over them easily. Depending on the token itself, additional | ||
128 | argument variables are filled with parameter values. | ||
129 | |||
130 | The tokens are defined below: | ||
131 | |||
132 | - CHR - Printable characters (32..255 but DEL (=127)) | ||
133 | - CTL - Control characters (0..31 but ESC (= 27), DEL) | ||
134 | - ESC - Escape codes of the form <ESC><CHR but `[]()+*#'> | ||
135 | - ESC_DE - Escape codes of the form <ESC><any of `()+*#%'> C | ||
136 | - CSI_PN - Escape codes of the form <ESC>'[' {Pn} ';' {Pn} C | ||
137 | - CSI_PS - Escape codes of the form <ESC>'[' {Pn} ';' ... C | ||
138 | - CSI_PR - Escape codes of the form <ESC>'[' '?' {Pn} ';' ... C | ||
139 | - VT52 - VT52 escape codes | ||
140 | - <ESC><Chr> | ||
141 | - <ESC>'Y'{Pc}{Pc} | ||
142 | - XTE_HA - Xterm hacks <ESC>`]' {Pn} `;' {Text} <BEL> | ||
143 | note that this is handled differently | ||
144 | |||
145 | The last two forms allow list of arguments. Since the elements of | ||
146 | the lists are treated individually the same way, they are passed | ||
147 | as individual tokens to the interpretation. Further, because the | ||
148 | meaning of the parameters are names (althought represented as numbers), | ||
149 | they are includes within the token ('N'). | ||
150 | |||
151 | */ | ||
152 | |||
153 | #define TY_CONSTR(T,A,N) ( ((((int)N) & 0xffff) << 16) | ((((int)A) & 0xff) << 8) | (((int)T) & 0xff) ) | ||
154 | |||
155 | #define TY_CHR___( ) TY_CONSTR(0,0,0) | ||
156 | #define TY_CTL___(A ) TY_CONSTR(1,A,0) | ||
157 | #define TY_ESC___(A ) TY_CONSTR(2,A,0) | ||
158 | #define TY_ESC_CS(A,B) TY_CONSTR(3,A,B) | ||
159 | #define TY_ESC_DE(A ) TY_CONSTR(4,A,0) | ||
160 | #define TY_CSI_PS(A,N) TY_CONSTR(5,A,N) | ||
161 | #define TY_CSI_PN(A ) TY_CONSTR(6,A,0) | ||
162 | #define TY_CSI_PR(A,N) TY_CONSTR(7,A,N) | ||
163 | |||
164 | #define TY_VT52__(A ) TY_CONSTR(8,A,0) | ||
165 | |||
166 | // Tokenizer --------------------------------------------------------------- -- | ||
167 | |||
168 | /* The tokenizers state | ||
169 | |||
170 | The state is represented by the buffer (pbuf, ppos), | ||
171 | and accompanied by decoded arguments kept in (argv,argc). | ||
172 | Note that they are kept internal in the tokenizer. | ||
173 | */ | ||
174 | |||
175 | void TEmuVt102::resetToken() | ||
176 | { | ||
177 | ppos = 0; argc = 0; argv[0] = 0; argv[1] = 0; | ||
178 | } | ||
179 | |||
180 | void TEmuVt102::addDigit(int dig) | ||
181 | { | ||
182 | argv[argc] = 10*argv[argc] + dig; | ||
183 | } | ||
184 | |||
185 | void TEmuVt102::addArgument() | ||
186 | { | ||
187 | argc = QMIN(argc+1,MAXARGS-1); | ||
188 | argv[argc] = 0; | ||
189 | } | ||
190 | |||
191 | void TEmuVt102::pushToToken(int cc) | ||
192 | { | ||
193 | pbuf[ppos] = cc; | ||
194 | ppos = QMIN(ppos+1,MAXPBUF-1); | ||
195 | } | ||
196 | |||
197 | // Character Classes used while decoding | ||
198 | |||
199 | #define CTL 1 | ||
200 | #define CHR 2 | ||
201 | #define CPN 4 | ||
202 | #define DIG 8 | ||
203 | #define SCS 16 | ||
204 | #define GRP 32 | ||
205 | |||
206 | void TEmuVt102::initTokenizer() | ||
207 | { int i; UINT8* s; | ||
208 | for(i = 0; i < 256; i++) tbl[ i] = 0; | ||
209 | for(i = 0; i < 32; i++) tbl[ i] |= CTL; | ||
210 | for(i = 32; i < 256; i++) tbl[ i] |= CHR; | ||
211 | for(s = (UINT8*)"@ABCDGHLMPXcdfry"; *s; s++) tbl[*s] |= CPN; | ||
212 | for(s = (UINT8*)"0123456789" ; *s; s++) tbl[*s] |= DIG; | ||
213 | for(s = (UINT8*)"()+*%" ; *s; s++) tbl[*s] |= SCS; | ||
214 | for(s = (UINT8*)"()+*#[]%" ; *s; s++) tbl[*s] |= GRP; | ||
215 | resetToken(); | ||
216 | } | ||
217 | |||
218 | /* Ok, here comes the nasty part of the decoder. | ||
219 | |||
220 | Instead of keeping an explicit state, we deduce it from the | ||
221 | token scanned so far. It is then immediately combined with | ||
222 | the current character to form a scanning decision. | ||
223 | |||
224 | This is done by the following defines. | ||
225 | |||
226 | - P is the length of the token scanned so far. | ||
227 | - L (often P-1) is the position on which contents we base a decision. | ||
228 | - C is a character or a group of characters (taken from 'tbl'). | ||
229 | |||
230 | Note that they need to applied in proper order. | ||
231 | */ | ||
232 | |||
233 | #define lec(P,L,C) (p == (P) && s[(L)] == (C)) | ||
234 | #define lun( ) (p == 1 && cc >= 32 ) | ||
235 | #define les(P,L,C) (p == (P) && s[L] < 256 && (tbl[s[(L)]] & (C)) == (C)) | ||
236 | #define eec(C) (p >= 3 && cc == (C)) | ||
237 | #define ees(C) (p >= 3 && cc < 256 && (tbl[ cc ] & (C)) == (C)) | ||
238 | #define eps(C) (p >= 3 && s[2] != '?' && cc < 256 && (tbl[ cc ] & (C)) == (C)) | ||
239 | #define epp( ) (p >= 3 && s[2] == '?' ) | ||
240 | #define egt( ) (p == 3 && s[2] == '>' ) | ||
241 | #define Xpe (ppos>=2 && pbuf[1] == ']' ) | ||
242 | #define Xte (Xpe && cc == 7 ) | ||
243 | #define ces(C) ( cc < 256 && (tbl[ cc ] & (C)) == (C) && !Xte) | ||
244 | |||
245 | #define ESC 27 | ||
246 | #define CNTL(c) ((c)-'@') | ||
247 | |||
248 | // process an incoming unicode character | ||
249 | |||
250 | void TEmuVt102::onRcvChar(int cc) | ||
251 | { int i; | ||
252 | |||
253 | if (cc == 127) return; //VT100: ignore. | ||
254 | |||
255 | if (ces( CTL)) | ||
256 | { // DEC HACK ALERT! Control Characters are allowed *within* esc sequences in VT100 | ||
257 | // This means, they do neither a resetToken nor a pushToToken. Some of them, do | ||
258 | // of course. Guess this originates from a weakly layered handling of the X-on | ||
259 | // X-off protocol, which comes really below this level. | ||
260 | if (cc == CNTL('X') || cc == CNTL('Z') || cc == ESC) resetToken(); //VT100: CAN or SUB | ||
261 | if (cc != ESC) { tau( TY_CTL___(cc+'@' ), 0, 0); return; } | ||
262 | } | ||
263 | |||
264 | pushToToken(cc); // advance the state | ||
265 | |||
266 | int* s = pbuf; | ||
267 | int p = ppos; | ||
268 | |||
269 | if (getMode(MODE_Ansi)) // decide on proper action | ||
270 | { | ||
271 | if (lec(1,0,ESC)) { return; } | ||
272 | if (les(2,1,GRP)) { return; } | ||
273 | if (Xte ) { XtermHack(); resetToken(); return; } | ||
274 | if (Xpe ) { return; } | ||
275 | if (lec(3,2,'?')) { return; } | ||
276 | if (lec(3,2,'>')) { return; } | ||
277 | if (lun( )) { tau( TY_CHR___(), applyCharset(cc), 0); resetToken(); return; } | ||
278 | if (lec(2,0,ESC)) { tau( TY_ESC___(s[1]), 0, 0); resetToken(); return; } | ||
279 | if (les(3,1,SCS)) { tau( TY_ESC_CS(s[1],s[2]), 0, 0); resetToken(); return; } | ||
280 | if (lec(3,1,'#')) { tau( TY_ESC_DE(s[2]), 0, 0); resetToken(); return; } | ||
281 | // if (egt( )) { tau( TY_CSI_PG(cc ), '>', 0); resetToken(); return; } | ||
282 | if (eps( CPN)) { tau( TY_CSI_PN(cc), argv[0],argv[1]); resetToken(); return; } | ||
283 | if (ees( DIG)) { addDigit(cc-'0'); return; } | ||
284 | if (eec( ';')) { addArgument(); return; } | ||
285 | for (i=0;i<=argc;i++) | ||
286 | if (epp( )) tau( TY_CSI_PR(cc,argv[i]), 0, 0); else | ||
287 | tau( TY_CSI_PS(cc,argv[i]), 0, 0); | ||
288 | resetToken(); | ||
289 | } | ||
290 | else // mode VT52 | ||
291 | { | ||
292 | if (lec(1,0,ESC)) return; | ||
293 | if (les(1,0,CHR)) { tau( TY_CHR___( ), s[0], 0); resetToken(); return; } | ||
294 | if (lec(2,1,'Y')) return; | ||
295 | if (lec(3,1,'Y')) return; | ||
296 | if (p < 4) { tau( TY_VT52__(s[1] ), 0, 0); resetToken(); return; } | ||
297 | tau( TY_VT52__(s[1] ), s[2],s[3]); resetToken(); return; | ||
298 | } | ||
299 | } | ||
300 | |||
301 | void TEmuVt102::XtermHack() | ||
302 | { int i,arg = 0; | ||
303 | for (i = 2; i < ppos && '0'<=pbuf[i] && pbuf[i]<'9' ; i++) | ||
304 | arg = 10*arg + (pbuf[i]-'0'); | ||
305 | if (pbuf[i] != ';') { ReportErrorToken(); return; } | ||
306 | QChar *str = new QChar[ppos-i-2]; | ||
307 | for (int j = 0; j < ppos-i-2; j++) str[j] = pbuf[i+1+j]; | ||
308 | QString unistr(str,ppos-i-2); | ||
309 | // arg == 1 doesn't change the title. In XTerm it only changes the icon name | ||
310 | // (btw: arg=0 changes title and icon, arg=1 only icon, arg=2 only title | ||
311 | if (arg == 0 || arg == 2) emit changeTitle(arg,unistr); | ||
312 | delete [] str; | ||
313 | } | ||
314 | |||
315 | // Interpreting Codes --------------------------------------------------------- | ||
316 | |||
317 | /* | ||
318 | Now that the incoming character stream is properly tokenized, | ||
319 | meaning is assigned to them. These are either operations of | ||
320 | the current screen, or of the emulation class itself. | ||
321 | |||
322 | The token to be interpreteted comes in as a machine word | ||
323 | possibly accompanied by two parameters. | ||
324 | |||
325 | Likewise, the operations assigned to, come with up to two | ||
326 | arguments. One could consider to make up a proper table | ||
327 | from the function below. | ||
328 | |||
329 | The technical reference manual provides more informations | ||
330 | about this mapping. | ||
331 | */ | ||
332 | |||
333 | void TEmuVt102::tau( int token, int p, int q ) | ||
334 | { | ||
335 | //scan_buffer_report(); | ||
336 | //if (token == TY_CHR___()) printf("%c",p); else | ||
337 | //printf("tau(%d,%d,%d, %d,%d)\n",(token>>0)&0xff,(token>>8)&0xff,(token>>16)&0xffff,p,q); | ||
338 | switch (token) | ||
339 | { | ||
340 | |||
341 | case TY_CHR___( ) : scr->ShowCharacter (p ); break; //UTF16 | ||
342 | |||
343 | // 127 DEL : ignored on input | ||
344 | |||
345 | case TY_CTL___('@' ) : /* NUL: ignored */ break; | ||
346 | case TY_CTL___('A' ) : /* SOH: ignored */ break; | ||
347 | case TY_CTL___('B' ) : /* STX: ignored */ break; | ||
348 | case TY_CTL___('C' ) : /* ETX: ignored */ break; | ||
349 | case TY_CTL___('D' ) : /* EOT: ignored */ break; | ||
350 | case TY_CTL___('E' ) : reportAnswerBack ( ); break; //VT100 | ||
351 | case TY_CTL___('F' ) : /* ACK: ignored */ break; | ||
352 | case TY_CTL___('G' ) : gui->Bell ( ); break; //VT100 | ||
353 | case TY_CTL___('H' ) : scr->BackSpace ( ); break; //VT100 | ||
354 | case TY_CTL___('I' ) : scr->Tabulate ( ); break; //VT100 | ||
355 | case TY_CTL___('J' ) : scr->NewLine ( ); break; //VT100 | ||
356 | case TY_CTL___('K' ) : scr->NewLine ( ); break; //VT100 | ||
357 | case TY_CTL___('L' ) : scr->NewLine ( ); break; //VT100 | ||
358 | case TY_CTL___('M' ) : scr->Return ( ); break; //VT100 | ||
359 | |||
360 | case TY_CTL___('N' ) : useCharset ( 1); break; //VT100 | ||
361 | case TY_CTL___('O' ) : useCharset ( 0); break; //VT100 | ||
362 | |||
363 | case TY_CTL___('P' ) : /* DLE: ignored */ break; | ||
364 | case TY_CTL___('Q' ) : /* DC1: XON continue */ break; //VT100 | ||
365 | case TY_CTL___('R' ) : /* DC2: ignored */ break; | ||
366 | case TY_CTL___('S' ) : /* DC3: XOFF halt */ break; //VT100 | ||
367 | case TY_CTL___('T' ) : /* DC4: ignored */ break; | ||
368 | case TY_CTL___('U' ) : /* NAK: ignored */ break; | ||
369 | case TY_CTL___('V' ) : /* SYN: ignored */ break; | ||
370 | case TY_CTL___('W' ) : /* ETB: ignored */ break; | ||
371 | case TY_CTL___('X' ) : scr->ShowCharacter ( 0x2592); break; //VT100 | ||
372 | case TY_CTL___('Y' ) : /* EM : ignored */ break; | ||
373 | case TY_CTL___('Z' ) : scr->ShowCharacter ( 0x2592); break; //VT100 | ||
374 | case TY_CTL___('[' ) : /* ESC: cannot be seen here. */ break; | ||
375 | case TY_CTL___('\\' ) : /* FS : ignored */ break; | ||
376 | case TY_CTL___(']' ) : /* GS : ignored */ break; | ||
377 | case TY_CTL___('^' ) : /* RS : ignored */ break; | ||
378 | case TY_CTL___('_' ) : /* US : ignored */ break; | ||
379 | |||
380 | case TY_ESC___('D' ) : scr->index ( ); break; //VT100 | ||
381 | case TY_ESC___('E' ) : scr->NextLine ( ); break; //VT100 | ||
382 | case TY_ESC___('H' ) : scr->changeTabStop (TRUE ); break; //VT100 | ||
383 | case TY_ESC___('M' ) : scr->reverseIndex ( ); break; //VT100 | ||
384 | case TY_ESC___('Z' ) : reportTerminalType ( ); break; | ||
385 | case TY_ESC___('c' ) : reset ( ); break; | ||
386 | |||
387 | case TY_ESC___('n' ) : useCharset ( 2); break; | ||
388 | case TY_ESC___('o' ) : useCharset ( 3); break; | ||
389 | case TY_ESC___('7' ) : saveCursor ( ); break; | ||
390 | case TY_ESC___('8' ) : restoreCursor ( ); break; | ||
391 | |||
392 | case TY_ESC___('=' ) : setMode (MODE_AppKeyPad); break; | ||
393 | case TY_ESC___('>' ) : resetMode (MODE_AppKeyPad); break; | ||
394 | case TY_ESC___('<' ) : setMode (MODE_Ansi ); break; //VT100 | ||
395 | |||
396 | case TY_ESC_CS('(', '0') : setCharset (0, '0'); break; //VT100 | ||
397 | case TY_ESC_CS('(', 'A') : setCharset (0, 'A'); break; //VT100 | ||
398 | case TY_ESC_CS('(', 'B') : setCharset (0, 'B'); break; //VT100 | ||
399 | |||
400 | case TY_ESC_CS(')', '0') : setCharset (1, '0'); break; //VT100 | ||
401 | case TY_ESC_CS(')', 'A') : setCharset (1, 'A'); break; //VT100 | ||
402 | case TY_ESC_CS(')', 'B') : setCharset (1, 'B'); break; //VT100 | ||
403 | |||
404 | case TY_ESC_CS('*', '0') : setCharset (2, '0'); break; //VT100 | ||
405 | case TY_ESC_CS('*', 'A') : setCharset (2, 'A'); break; //VT100 | ||
406 | case TY_ESC_CS('*', 'B') : setCharset (2, 'B'); break; //VT100 | ||
407 | |||
408 | case TY_ESC_CS('+', '0') : setCharset (3, '0'); break; //VT100 | ||
409 | case TY_ESC_CS('+', 'A') : setCharset (3, 'A'); break; //VT100 | ||
410 | case TY_ESC_CS('+', 'B') : setCharset (3, 'B'); break; //VT100 | ||
411 | |||
412 | case TY_ESC_CS('%', 'G') : setCodec (1 ); break; //LINUX | ||
413 | case TY_ESC_CS('%', '@') : setCodec (0 ); break; //LINUX | ||
414 | |||
415 | case TY_ESC_DE('3' ) : /* IGNORED: double high, top half */ break; | ||
416 | case TY_ESC_DE('4' ) : /* IGNORED: double high, bottom half */ break; | ||
417 | case TY_ESC_DE('5' ) : /* IGNORED: single width, single high*/ break; | ||
418 | case TY_ESC_DE('6' ) : /* IGNORED: double width, single high*/ break; | ||
419 | case TY_ESC_DE('8' ) : scr->helpAlign ( ); break; | ||
420 | |||
421 | case TY_CSI_PS('K', 0) : scr->clearToEndOfLine ( ); break; | ||
422 | case TY_CSI_PS('K', 1) : scr->clearToBeginOfLine ( ); break; | ||
423 | case TY_CSI_PS('K', 2) : scr->clearEntireLine ( ); break; | ||
424 | case TY_CSI_PS('J', 0) : scr->clearToEndOfScreen ( ); break; | ||
425 | case TY_CSI_PS('J', 1) : scr->clearToBeginOfScreen ( ); break; | ||
426 | case TY_CSI_PS('J', 2) : scr->clearEntireScreen ( ); break; | ||
427 | case TY_CSI_PS('g', 0) : scr->changeTabStop (FALSE ); break; //VT100 | ||
428 | case TY_CSI_PS('g', 3) : scr->clearTabStops ( ); break; //VT100 | ||
429 | case TY_CSI_PS('h', 4) : scr-> setMode (MODE_Insert ); break; | ||
430 | case TY_CSI_PS('h', 20) : setMode (MODE_NewLine ); break; | ||
431 | case TY_CSI_PS('i', 0) : /* IGNORE: attached printer */ break; //VT100 | ||
432 | case TY_CSI_PS('l', 4) : scr-> resetMode (MODE_Insert ); break; | ||
433 | case TY_CSI_PS('l', 20) : resetMode (MODE_NewLine ); break; | ||
434 | |||
435 | case TY_CSI_PS('m', 0) : scr->setDefaultRendition ( ); break; | ||
436 | case TY_CSI_PS('m', 1) : scr-> setRendition (RE_BOLD ); break; //VT100 | ||
437 | case TY_CSI_PS('m', 4) : scr-> setRendition (RE_UNDERLINE); break; //VT100 | ||
438 | case TY_CSI_PS('m', 5) : scr-> setRendition (RE_BLINK ); break; //VT100 | ||
439 | case TY_CSI_PS('m', 7) : scr-> setRendition (RE_REVERSE ); break; | ||
440 | case TY_CSI_PS('m', 10) : /* IGNORED: mapping related */ break; //LINUX | ||
441 | case TY_CSI_PS('m', 11) : /* IGNORED: mapping related */ break; //LINUX | ||
442 | case TY_CSI_PS('m', 12) : /* IGNORED: mapping related */ break; //LINUX | ||
443 | case TY_CSI_PS('m', 22) : scr->resetRendition (RE_BOLD ); break; | ||
444 | case TY_CSI_PS('m', 24) : scr->resetRendition (RE_UNDERLINE); break; | ||
445 | case TY_CSI_PS('m', 25) : scr->resetRendition (RE_BLINK ); break; | ||
446 | case TY_CSI_PS('m', 27) : scr->resetRendition (RE_REVERSE ); break; | ||
447 | |||
448 | case TY_CSI_PS('m', 30) : scr->setForeColor ( 0); break; | ||
449 | case TY_CSI_PS('m', 31) : scr->setForeColor ( 1); break; | ||
450 | case TY_CSI_PS('m', 32) : scr->setForeColor ( 2); break; | ||
451 | case TY_CSI_PS('m', 33) : scr->setForeColor ( 3); break; | ||
452 | case TY_CSI_PS('m', 34) : scr->setForeColor ( 4); break; | ||
453 | case TY_CSI_PS('m', 35) : scr->setForeColor ( 5); break; | ||
454 | case TY_CSI_PS('m', 36) : scr->setForeColor ( 6); break; | ||
455 | case TY_CSI_PS('m', 37) : scr->setForeColor ( 7); break; | ||
456 | case TY_CSI_PS('m', 39) : scr->setForeColorToDefault( ); break; | ||
457 | |||
458 | case TY_CSI_PS('m', 40) : scr->setBackColor ( 0); break; | ||
459 | case TY_CSI_PS('m', 41) : scr->setBackColor ( 1); break; | ||
460 | case TY_CSI_PS('m', 42) : scr->setBackColor ( 2); break; | ||
461 | case TY_CSI_PS('m', 43) : scr->setBackColor ( 3); break; | ||
462 | case TY_CSI_PS('m', 44) : scr->setBackColor ( 4); break; | ||
463 | case TY_CSI_PS('m', 45) : scr->setBackColor ( 5); break; | ||
464 | case TY_CSI_PS('m', 46) : scr->setBackColor ( 6); break; | ||
465 | case TY_CSI_PS('m', 47) : scr->setBackColor ( 7); break; | ||
466 | case TY_CSI_PS('m', 49) : scr->setBackColorToDefault( ); break; | ||
467 | |||
468 | case TY_CSI_PS('m', 90) : scr->setForeColor ( 8); break; | ||
469 | case TY_CSI_PS('m', 91) : scr->setForeColor ( 9); break; | ||
470 | case TY_CSI_PS('m', 92) : scr->setForeColor ( 10); break; | ||
471 | case TY_CSI_PS('m', 93) : scr->setForeColor ( 11); break; | ||
472 | case TY_CSI_PS('m', 94) : scr->setForeColor ( 12); break; | ||
473 | case TY_CSI_PS('m', 95) : scr->setForeColor ( 13); break; | ||
474 | case TY_CSI_PS('m', 96) : scr->setForeColor ( 14); break; | ||
475 | case TY_CSI_PS('m', 97) : scr->setForeColor ( 15); break; | ||
476 | |||
477 | case TY_CSI_PS('m', 100) : scr->setBackColor ( 8); break; | ||
478 | case TY_CSI_PS('m', 101) : scr->setBackColor ( 9); break; | ||
479 | case TY_CSI_PS('m', 102) : scr->setBackColor ( 10); break; | ||
480 | case TY_CSI_PS('m', 103) : scr->setBackColor ( 11); break; | ||
481 | case TY_CSI_PS('m', 104) : scr->setBackColor ( 12); break; | ||
482 | case TY_CSI_PS('m', 105) : scr->setBackColor ( 13); break; | ||
483 | case TY_CSI_PS('m', 106) : scr->setBackColor ( 14); break; | ||
484 | case TY_CSI_PS('m', 107) : scr->setBackColor ( 15); break; | ||
485 | |||
486 | case TY_CSI_PS('n', 5) : reportStatus ( ); break; | ||
487 | case TY_CSI_PS('n', 6) : reportCursorPosition ( ); break; | ||
488 | case TY_CSI_PS('q', 0) : /* IGNORED: LEDs off */ break; //VT100 | ||
489 | case TY_CSI_PS('q', 1) : /* IGNORED: LED1 on */ break; //VT100 | ||
490 | case TY_CSI_PS('q', 2) : /* IGNORED: LED2 on */ break; //VT100 | ||
491 | case TY_CSI_PS('q', 3) : /* IGNORED: LED3 on */ break; //VT100 | ||
492 | case TY_CSI_PS('q', 4) : /* IGNORED: LED4 on */ break; //VT100 | ||
493 | case TY_CSI_PS('x', 0) : reportTerminalParms ( 2); break; //VT100 | ||
494 | case TY_CSI_PS('x', 1) : reportTerminalParms ( 3); break; //VT100 | ||
495 | |||
496 | case TY_CSI_PN('@' ) : scr->insertChars (p ); break; | ||
497 | case TY_CSI_PN('A' ) : scr->cursorUp (p ); break; //VT100 | ||
498 | case TY_CSI_PN('B' ) : scr->cursorDown (p ); break; //VT100 | ||
499 | case TY_CSI_PN('C' ) : scr->cursorRight (p ); break; //VT100 | ||
500 | case TY_CSI_PN('D' ) : scr->cursorLeft (p ); break; //VT100 | ||
501 | case TY_CSI_PN('G' ) : scr->setCursorX (p ); break; //LINUX | ||
502 | case TY_CSI_PN('H' ) : scr->setCursorYX (p, q); break; //VT100 | ||
503 | case TY_CSI_PN('L' ) : scr->insertLines (p ); break; | ||
504 | case TY_CSI_PN('M' ) : scr->deleteLines (p ); break; | ||
505 | case TY_CSI_PN('P' ) : scr->deleteChars (p ); break; | ||
506 | case TY_CSI_PN('X' ) : scr->eraseChars (p ); break; | ||
507 | case TY_CSI_PN('c' ) : reportTerminalType ( ); break; //VT100 | ||
508 | case TY_CSI_PN('d' ) : scr->setCursorY (p ); break; //LINUX | ||
509 | case TY_CSI_PN('f' ) : scr->setCursorYX (p, q); break; //VT100 | ||
510 | case TY_CSI_PN('r' ) : scr->setMargins (p, q); break; //VT100 | ||
511 | case TY_CSI_PN('y' ) : /* IGNORED: Confidence test */ break; //VT100 | ||
512 | |||
513 | case TY_CSI_PR('h', 1) : setMode (MODE_AppCuKeys); break; //VT100 | ||
514 | case TY_CSI_PR('l', 1) : resetMode (MODE_AppCuKeys); break; //VT100 | ||
515 | case TY_CSI_PR('s', 1) : saveMode (MODE_AppCuKeys); break; //FIXME | ||
516 | case TY_CSI_PR('r', 1) : restoreMode (MODE_AppCuKeys); break; //FIXME | ||
517 | |||
518 | case TY_CSI_PR('l', 2) : resetMode (MODE_Ansi ); break; //VT100 | ||
519 | |||
520 | case TY_CSI_PR('h', 3) : setColumns ( 132); break; //VT100 | ||
521 | case TY_CSI_PR('l', 3) : setColumns ( 80); break; //VT100 | ||
522 | |||
523 | case TY_CSI_PR('h', 4) : /* IGNORED: soft scrolling */ break; //VT100 | ||
524 | case TY_CSI_PR('l', 4) : /* IGNORED: soft scrolling */ break; //VT100 | ||
525 | |||
526 | case TY_CSI_PR('h', 5) : scr-> setMode (MODE_Screen ); break; //VT100 | ||
527 | case TY_CSI_PR('l', 5) : scr-> resetMode (MODE_Screen ); break; //VT100 | ||
528 | |||
529 | case TY_CSI_PR('h', 6) : scr-> setMode (MODE_Origin ); break; //VT100 | ||
530 | case TY_CSI_PR('l', 6) : scr-> resetMode (MODE_Origin ); break; //VT100 | ||
531 | case TY_CSI_PR('s', 6) : scr-> saveMode (MODE_Origin ); break; //FIXME | ||
532 | case TY_CSI_PR('r', 6) : scr->restoreMode (MODE_Origin ); break; //FIXME | ||
533 | |||
534 | case TY_CSI_PR('h', 7) : scr-> setMode (MODE_Wrap ); break; //VT100 | ||
535 | case TY_CSI_PR('l', 7) : scr-> resetMode (MODE_Wrap ); break; //VT100 | ||
536 | case TY_CSI_PR('s', 7) : scr-> saveMode (MODE_Wrap ); break; //FIXME | ||
537 | case TY_CSI_PR('r', 7) : scr->restoreMode (MODE_Wrap ); break; //FIXME | ||
538 | |||
539 | case TY_CSI_PR('h', 8) : /* IGNORED: autorepeat on */ break; //VT100 | ||
540 | case TY_CSI_PR('l', 8) : /* IGNORED: autorepeat off */ break; //VT100 | ||
541 | |||
542 | case TY_CSI_PR('h', 9) : /* IGNORED: interlace */ break; //VT100 | ||
543 | case TY_CSI_PR('l', 9) : /* IGNORED: interlace */ break; //VT100 | ||
544 | |||
545 | case TY_CSI_PR('h', 25) : setMode (MODE_Cursor ); break; //VT100 | ||
546 | case TY_CSI_PR('l', 25) : resetMode (MODE_Cursor ); break; //VT100 | ||
547 | |||
548 | case TY_CSI_PR('h', 41) : /* IGNORED: obsolete more(1) fix */ break; //XTERM | ||
549 | case TY_CSI_PR('l', 41) : /* IGNORED: obsolete more(1) fix */ break; //XTERM | ||
550 | case TY_CSI_PR('s', 41) : /* IGNORED: obsolete more(1) fix */ break; //XTERM | ||
551 | case TY_CSI_PR('r', 41) : /* IGNORED: obsolete more(1) fix */ break; //XTERM | ||
552 | |||
553 | case TY_CSI_PR('h', 47) : setMode (MODE_AppScreen); break; //VT100 | ||
554 | case TY_CSI_PR('l', 47) : resetMode (MODE_AppScreen); break; //VT100 | ||
555 | |||
556 | case TY_CSI_PR('h', 1000) : setMode (MODE_Mouse1000); break; //XTERM | ||
557 | case TY_CSI_PR('l', 1000) : resetMode (MODE_Mouse1000); break; //XTERM | ||
558 | case TY_CSI_PR('s', 1000) : saveMode (MODE_Mouse1000); break; //XTERM | ||
559 | case TY_CSI_PR('r', 1000) : restoreMode (MODE_Mouse1000); break; //XTERM | ||
560 | |||
561 | case TY_CSI_PR('h', 1001) : /* IGNORED: hilite mouse tracking */ break; //XTERM | ||
562 | case TY_CSI_PR('l', 1001) : /* IGNORED: hilite mouse tracking */ break; //XTERM | ||
563 | case TY_CSI_PR('s', 1001) : /* IGNORED: hilite mouse tracking */ break; //XTERM | ||
564 | case TY_CSI_PR('r', 1001) : /* IGNORED: hilite mouse tracking */ break; //XTERM | ||
565 | |||
566 | case TY_CSI_PR('h', 1047) : setMode (MODE_AppScreen); break; //XTERM | ||
567 | case TY_CSI_PR('l', 1047) : resetMode (MODE_AppScreen); break; //XTERM | ||
568 | |||
569 | //FIXME: Unitoken: save translations | ||
570 | case TY_CSI_PR('h', 1048) : saveCursor ( ); break; //XTERM | ||
571 | case TY_CSI_PR('l', 1048) : restoreCursor ( ); break; //XTERM | ||
572 | |||
573 | //FIXME: every once new sequences like this pop up in xterm. | ||
574 | // Here's a guess of what they could mean. | ||
575 | case TY_CSI_PR('h', 1049) : setMode (MODE_AppScreen); break; //XTERM | ||
576 | case TY_CSI_PR('l', 1049) : resetMode (MODE_AppScreen); break; //XTERM | ||
577 | |||
578 | //FIXME: when changing between vt52 and ansi mode evtl do some resetting. | ||
579 | case TY_VT52__('A' ) : scr->cursorUp ( 1); break; //VT52 | ||
580 | case TY_VT52__('B' ) : scr->cursorDown ( 1); break; //VT52 | ||
581 | case TY_VT52__('C' ) : scr->cursorRight ( 1); break; //VT52 | ||
582 | case TY_VT52__('D' ) : scr->cursorLeft ( 1); break; //VT52 | ||
583 | |||
584 | case TY_VT52__('F' ) : setAndUseCharset (0, '0'); break; //VT52 | ||
585 | case TY_VT52__('G' ) : setAndUseCharset (0, 'B'); break; //VT52 | ||
586 | |||
587 | case TY_VT52__('H' ) : scr->setCursorYX (1,1 ); break; //VT52 | ||
588 | case TY_VT52__('I' ) : scr->reverseIndex ( ); break; //VT52 | ||
589 | case TY_VT52__('J' ) : scr->clearToEndOfScreen ( ); break; //VT52 | ||
590 | case TY_VT52__('K' ) : scr->clearToEndOfLine ( ); break; //VT52 | ||
591 | case TY_VT52__('Y' ) : scr->setCursorYX (p-31,q-31 ); break; //VT52 | ||
592 | case TY_VT52__('Z' ) : reportTerminalType ( ); break; //VT52 | ||
593 | case TY_VT52__('<' ) : setMode (MODE_Ansi ); break; //VT52 | ||
594 | case TY_VT52__('=' ) : setMode (MODE_AppKeyPad); break; //VT52 | ||
595 | case TY_VT52__('>' ) : resetMode (MODE_AppKeyPad); break; //VT52 | ||
596 | |||
597 | default : ReportErrorToken(); break; | ||
598 | }; | ||
599 | } | ||
600 | |||
601 | /* ------------------------------------------------------------------------- */ | ||
602 | /* */ | ||
603 | /* Terminal to Host protocol */ | ||
604 | /* */ | ||
605 | /* ------------------------------------------------------------------------- */ | ||
606 | |||
607 | /* | ||
608 | Outgoing bytes originate from several sources: | ||
609 | |||
610 | - Replies to Enquieries. | ||
611 | - Mouse Events | ||
612 | - Keyboard Events | ||
613 | */ | ||
614 | |||
615 | /*! | ||
616 | */ | ||
617 | |||
618 | void TEmuVt102::sendString(const char* s) | ||
619 | { | ||
620 | emit sndBlock(s,strlen(s)); | ||
621 | } | ||
622 | |||
623 | // Replies ----------------------------------------------------------------- -- | ||
624 | |||
625 | // This section copes with replies send as response to an enquiery control code. | ||
626 | |||
627 | /*! | ||
628 | */ | ||
629 | |||
630 | void TEmuVt102::reportCursorPosition() | ||
631 | { char tmp[20]; | ||
632 | sprintf(tmp,"\033[%d;%dR",scr->getCursorY()+1,scr->getCursorX()+1); | ||
633 | sendString(tmp); | ||
634 | } | ||
635 | |||
636 | /* | ||
637 | What follows here is rather obsolete and faked stuff. | ||
638 | The correspondent enquieries are neverthenless issued. | ||
639 | */ | ||
640 | |||
641 | /*! | ||
642 | */ | ||
643 | |||
644 | void TEmuVt102::reportTerminalType() | ||
645 | { | ||
646 | //FIXME: should change? | ||
647 | if (getMode(MODE_Ansi)) | ||
648 | // sendString("\033[?1;2c"); // I'm a VT100 with AP0 //FIXME: send only in response to ^[[0c | ||
649 | sendString("\033[>0;115;0c"); // I'm a VT220 //FIXME: send only in response to ^[[>c | ||
650 | else | ||
651 | sendString("\033/Z"); // I'm a VT52 | ||
652 | } | ||
653 | |||
654 | void TEmuVt102::reportTerminalParms(int p) | ||
655 | // DECREPTPARM | ||
656 | { char tmp[100]; | ||
657 | sprintf(tmp,"\033[%d;1;1;112;112;1;0x",p); // not really true. | ||
658 | sendString(tmp); | ||
659 | } | ||
660 | |||
661 | /*! | ||
662 | */ | ||
663 | |||
664 | void TEmuVt102::reportStatus() | ||
665 | { | ||
666 | sendString("\033[0n"); //VT100. Device status report. 0 = Ready. | ||
667 | } | ||
668 | |||
669 | /*! | ||
670 | */ | ||
671 | |||
672 | #define ANSWER_BACK "" // This is really obsolete VT100 stuff. | ||
673 | |||
674 | void TEmuVt102::reportAnswerBack() | ||
675 | { | ||
676 | sendString(ANSWER_BACK); | ||
677 | } | ||
678 | |||
679 | // Mouse Handling ---------------------------------------------------------- -- | ||
680 | |||
681 | /*! | ||
682 | Mouse clicks are possibly reported to the client | ||
683 | application if it has issued interest in them. | ||
684 | They are normally consumed by the widget for copy | ||
685 | and paste, but may be propagated from the widget | ||
686 | when gui->setMouseMarks is set via setMode(MODE_Mouse1000). | ||
687 | |||
688 | `x',`y' are 1-based. | ||
689 | `ev' (event) indicates the button pressed (0-2) | ||
690 | or a general mouse release (3). | ||
691 | */ | ||
692 | |||
693 | void TEmuVt102::onMouse( int cb, int cx, int cy ) | ||
694 | { char tmp[20]; | ||
695 | if (!connected) return; | ||
696 | sprintf(tmp,"\033[M%c%c%c",cb+040,cx+040,cy+040); | ||
697 | sendString(tmp); | ||
698 | } | ||
699 | |||
700 | // Keyboard Handling ------------------------------------------------------- -- | ||
701 | |||
702 | #define encodeMode(M,B) BITS(B,getMode(M)) | ||
703 | #define encodeStat(M,B) BITS(B,((ev->state() & (M)) == (M))) | ||
704 | |||
705 | /* | ||
706 | Keyboard event handling has been simplified somewhat by pushing | ||
707 | the complications towards a configuration file [see KeyTrans class]. | ||
708 | */ | ||
709 | |||
710 | void TEmuVt102::onKeyPress( QKeyEvent* ev ) | ||
711 | { | ||
712 | if (!connected) return; // someone else gets the keys | ||
713 | |||
714 | //printf("State/Key: 0x%04x 0x%04x (%d,%d)\n",ev->state(),ev->key(),ev->text().length(),ev->text().length()?ev->text().ascii()[0]:0); | ||
715 | |||
716 | // revert to non-history when typing | ||
717 | if (scr->getHistCursor() != scr->getHistLines()); | ||
718 | scr->setHistCursor(scr->getHistLines()); | ||
719 | |||
720 | // lookup in keyboard translation table ... | ||
721 | int cmd; const char* txt; int len; | ||
722 | if (keytrans->findEntry(ev->key(), encodeMode(MODE_NewLine , BITS_NewLine ) + // OLD, | ||
723 | encodeMode(MODE_Ansi , BITS_Ansi ) + // OBSOLETE, | ||
724 | encodeMode(MODE_AppCuKeys, BITS_AppCuKeys ) + // VT100 stuff | ||
725 | encodeStat(ControlButton , BITS_Control ) + | ||
726 | encodeStat(ShiftButton , BITS_Shift ) + | ||
727 | encodeStat(AltButton , BITS_Alt ), | ||
728 | &cmd, &txt, &len )) | ||
729 | //printf("cmd: %d, %s, %d\n",cmd,txt,len); | ||
730 | switch(cmd) // ... and execute if found. | ||
731 | { | ||
732 | case CMD_emitSelection : gui->emitSelection(); return; | ||
733 | case CMD_scrollPageUp : gui->doScroll(-gui->Lines()/2); return; | ||
734 | case CMD_scrollPageDown : gui->doScroll(+gui->Lines()/2); return; | ||
735 | case CMD_scrollLineUp : gui->doScroll(-1 ); return; | ||
736 | case CMD_scrollLineDown : gui->doScroll(+1 ); return; | ||
737 | case CMD_send : emit sndBlock(txt,len); return; | ||
738 | case CMD_prevSession : emit prevSession(); return; | ||
739 | case CMD_nextSession : emit nextSession(); return; | ||
740 | } | ||
741 | |||
742 | // fall back handling | ||
743 | if (!ev->text().isEmpty()) | ||
744 | { | ||
745 | if (ev->state() & AltButton) sendString("\033"); // ESC, this is the ALT prefix | ||
746 | QCString s = codec->fromUnicode(ev->text()); // encode for application | ||
747 | emit sndBlock(s.data(),s.length()); // we may well have s.length() > 1 | ||
748 | return; | ||
749 | } | ||
750 | } | ||
751 | |||
752 | /* ------------------------------------------------------------------------- */ | ||
753 | /* */ | ||
754 | /* VT100 Charsets */ | ||
755 | /* */ | ||
756 | /* ------------------------------------------------------------------------- */ | ||
757 | |||
758 | // Character Set Conversion ------------------------------------------------ -- | ||
759 | |||
760 | /* | ||
761 | The processing contains a VT100 specific code translation layer. | ||
762 | It's still in use and mainly responsible for the line drawing graphics. | ||
763 | |||
764 | These and some other glyphs are assigned to codes (0x5f-0xfe) | ||
765 | normally occupied by the latin letters. Since this codes also | ||
766 | appear within control sequences, the extra code conversion | ||
767 | does not permute with the tokenizer and is placed behind it | ||
768 | in the pipeline. It only applies to tokens, which represent | ||
769 | plain characters. | ||
770 | |||
771 | This conversion it eventually continued in TEWidget.C, since | ||
772 | it might involve VT100 enhanced fonts, which have these | ||
773 | particular glyphs allocated in (0x00-0x1f) in their code page. | ||
774 | */ | ||
775 | |||
776 | #define CHARSET charset[scr==screen[1]] | ||
777 | |||
778 | // Apply current character map. | ||
779 | |||
780 | unsigned short TEmuVt102::applyCharset(unsigned short c) | ||
781 | { | ||
782 | if (CHARSET.graphic && 0x5f <= c && c <= 0x7e) return vt100_graphics[c-0x5f]; | ||
783 | if (CHARSET.pound && c == '#' ) return 0xa3; //This mode is obsolete | ||
784 | return c; | ||
785 | } | ||
786 | |||
787 | /* | ||
788 | "Charset" related part of the emulation state. | ||
789 | This configures the VT100 charset filter. | ||
790 | |||
791 | While most operation work on the current screen, | ||
792 | the following two are different. | ||
793 | */ | ||
794 | |||
795 | void TEmuVt102::resetCharset(int scrno) | ||
796 | { | ||
797 | charset[scrno].cu_cs = 0; | ||
798 | strncpy(charset[scrno].charset,"BBBB",4); | ||
799 | charset[scrno].sa_graphic = FALSE; | ||
800 | charset[scrno].sa_pound = FALSE; | ||
801 | charset[scrno].graphic = FALSE; | ||
802 | charset[scrno].pound = FALSE; | ||
803 | } | ||
804 | |||
805 | /*! | ||
806 | */ | ||
807 | |||
808 | void TEmuVt102::setCharset(int n, int cs) // on both screens. | ||
809 | { | ||
810 | charset[0].charset[n&3] = cs; useCharset(charset[0].cu_cs); | ||
811 | charset[1].charset[n&3] = cs; useCharset(charset[1].cu_cs); | ||
812 | } | ||
813 | |||
814 | /*! | ||
815 | */ | ||
816 | |||
817 | void TEmuVt102::setAndUseCharset(int n, int cs) | ||
818 | { | ||
819 | CHARSET.charset[n&3] = cs; | ||
820 | useCharset(n&3); | ||
821 | } | ||
822 | |||
823 | /*! | ||
824 | */ | ||
825 | |||
826 | void TEmuVt102::useCharset(int n) | ||
827 | { | ||
828 | CHARSET.cu_cs = n&3; | ||
829 | CHARSET.graphic = (CHARSET.charset[n&3] == '0'); | ||
830 | CHARSET.pound = (CHARSET.charset[n&3] == 'A'); //This mode is obsolete | ||
831 | } | ||
832 | |||
833 | /*! Save the cursor position and the rendition attribute settings. */ | ||
834 | |||
835 | void TEmuVt102::saveCursor() | ||
836 | { | ||
837 | CHARSET.sa_graphic = CHARSET.graphic; | ||
838 | CHARSET.sa_pound = CHARSET.pound; //This mode is obsolete | ||
839 | // we are not clear about these | ||
840 | //sa_charset = charsets[cScreen->charset]; | ||
841 | //sa_charset_num = cScreen->charset; | ||
842 | scr->saveCursor(); | ||
843 | } | ||
844 | |||
845 | /*! Restore the cursor position and the rendition attribute settings. */ | ||
846 | |||
847 | void TEmuVt102::restoreCursor() | ||
848 | { | ||
849 | CHARSET.graphic = CHARSET.sa_graphic; | ||
850 | CHARSET.pound = CHARSET.sa_pound; //This mode is obsolete | ||
851 | scr->restoreCursor(); | ||
852 | } | ||
853 | |||
854 | /* ------------------------------------------------------------------------- */ | ||
855 | /* */ | ||
856 | /* Mode Operations */ | ||
857 | /* */ | ||
858 | /* ------------------------------------------------------------------------- */ | ||
859 | |||
860 | /* | ||
861 | Some of the emulations state is either added to the state of the screens. | ||
862 | |||
863 | This causes some scoping problems, since different emulations choose to | ||
864 | located the mode either to the current screen or to both. | ||
865 | |||
866 | For strange reasons, the extend of the rendition attributes ranges over | ||
867 | all screens and not over the actual screen. | ||
868 | |||
869 | We decided on the precise precise extend, somehow. | ||
870 | */ | ||
871 | |||
872 | // "Mode" related part of the state. These are all booleans. | ||
873 | |||
874 | void TEmuVt102::resetModes() | ||
875 | { | ||
876 | resetMode(MODE_Mouse1000); saveMode(MODE_Mouse1000); | ||
877 | resetMode(MODE_AppScreen); saveMode(MODE_AppScreen); | ||
878 | // here come obsolete modes | ||
879 | resetMode(MODE_AppCuKeys); saveMode(MODE_AppCuKeys); | ||
880 | resetMode(MODE_NewLine ); | ||
881 | setMode(MODE_Ansi ); | ||
882 | } | ||
883 | |||
884 | void TEmuVt102::setMode(int m) | ||
885 | { | ||
886 | currParm.mode[m] = TRUE; | ||
887 | switch (m) | ||
888 | { | ||
889 | case MODE_Mouse1000 : gui->setMouseMarks(FALSE); | ||
890 | break; | ||
891 | case MODE_AppScreen : screen[1]->clearSelection(); | ||
892 | screen[1]->clearEntireScreen(); | ||
893 | setScreen(1); | ||
894 | break; | ||
895 | } | ||
896 | if (m < MODES_SCREEN || m == MODE_NewLine) | ||
897 | { | ||
898 | screen[0]->setMode(m); | ||
899 | screen[1]->setMode(m); | ||
900 | } | ||
901 | } | ||
902 | |||
903 | void TEmuVt102::resetMode(int m) | ||
904 | { | ||
905 | currParm.mode[m] = FALSE; | ||
906 | switch (m) | ||
907 | { | ||
908 | case MODE_Mouse1000 : gui->setMouseMarks(TRUE); | ||
909 | break; | ||
910 | case MODE_AppScreen : screen[0]->clearSelection(); | ||
911 | setScreen(0); | ||
912 | break; | ||
913 | } | ||
914 | if (m < MODES_SCREEN || m == MODE_NewLine) | ||
915 | { | ||
916 | screen[0]->resetMode(m); | ||
917 | screen[1]->resetMode(m); | ||
918 | } | ||
919 | } | ||
920 | |||
921 | void TEmuVt102::saveMode(int m) | ||
922 | { | ||
923 | saveParm.mode[m] = currParm.mode[m]; | ||
924 | } | ||
925 | |||
926 | void TEmuVt102::restoreMode(int m) | ||
927 | { | ||
928 | if(saveParm.mode[m]) setMode(m); else resetMode(m); | ||
929 | } | ||
930 | |||
931 | BOOL TEmuVt102::getMode(int m) | ||
932 | { | ||
933 | return currParm.mode[m]; | ||
934 | } | ||
935 | |||
936 | void TEmuVt102::setConnect(bool c) | ||
937 | { | ||
938 | TEmulation::setConnect(c); | ||
939 | if (c) | ||
940 | { // refresh mouse mode | ||
941 | if (getMode(MODE_Mouse1000)) | ||
942 | setMode(MODE_Mouse1000); | ||
943 | else | ||
944 | resetMode(MODE_Mouse1000); | ||
945 | } | ||
946 | } | ||
947 | |||
948 | /* ------------------------------------------------------------------------- */ | ||
949 | /* */ | ||
950 | /* Diagnostic */ | ||
951 | /* */ | ||
952 | /* ------------------------------------------------------------------------- */ | ||
953 | |||
954 | /*! shows the contents of the scan buffer. | ||
955 | |||
956 | This functions is used for diagnostics. It is called by \e ReportErrorToken | ||
957 | to inform about strings that cannot be decoded or handled by the emulation. | ||
958 | |||
959 | \sa ReportErrorToken | ||
960 | */ | ||
961 | |||
962 | /*! | ||
963 | */ | ||
964 | |||
965 | static void hexdump(int* s, int len) | ||
966 | { int i; | ||
967 | for (i = 0; i < len; i++) | ||
968 | { | ||
969 | if (s[i] == '\\') | ||
970 | printf("\\\\"); | ||
971 | else | ||
972 | if ((s[i]) > 32 && s[i] < 127) | ||
973 | printf("%c",s[i]); | ||
974 | else | ||
975 | printf("\\%04x(hex)",s[i]); | ||
976 | } | ||
977 | } | ||
978 | |||
979 | void TEmuVt102::scan_buffer_report() | ||
980 | { | ||
981 | if (ppos == 0 || ppos == 1 && (pbuf[0] & 0xff) >= 32) return; | ||
982 | printf("token: "); hexdump(pbuf,ppos); printf("\n"); | ||
983 | } | ||
984 | |||
985 | /*! | ||
986 | */ | ||
987 | |||
988 | void TEmuVt102::ReportErrorToken() | ||
989 | { | ||
990 | printf("undecodable "); scan_buffer_report(); | ||
991 | } | ||
diff --git a/core/apps/embeddedkonsole/TEmuVt102.h b/core/apps/embeddedkonsole/TEmuVt102.h new file mode 100644 index 0000000..a448a71 --- a/dev/null +++ b/core/apps/embeddedkonsole/TEmuVt102.h | |||
@@ -0,0 +1,135 @@ | |||
1 | /* -------------------------------------------------------------------------- */ | ||
2 | /* */ | ||
3 | /* [TEmuVt102.h] X Terminal Emulation */ | ||
4 | /* */ | ||
5 | /* -------------------------------------------------------------------------- */ | ||
6 | /* */ | ||
7 | /* Copyright (c) 1997,1998 by Lars Doelle <lars.doelle@on-line.de> */ | ||
8 | /* */ | ||
9 | /* This file is part of Konsole - an X terminal for KDE */ | ||
10 | /* */ | ||
11 | /* -------------------------------------------------------------------------- */ | ||
12 | /* */ | ||
13 | /* Ported Konsole to Qt/Embedded */ | ||
14 | /* */ | ||
15 | /* Copyright (C) 2000 by John Ryland <jryland@trolltech.com> */ | ||
16 | /* */ | ||
17 | /* -------------------------------------------------------------------------- */ | ||
18 | |||
19 | #ifndef VT102EMU_H | ||
20 | #define VT102EMU_H | ||
21 | |||
22 | #include "TEWidget.h" | ||
23 | #include "TEScreen.h" | ||
24 | #include "TEmulation.h" | ||
25 | #include <qtimer.h> | ||
26 | #include <stdio.h> | ||
27 | |||
28 | // | ||
29 | |||
30 | #define MODE_AppScreen (MODES_SCREEN+0) | ||
31 | #define MODE_AppCuKeys (MODES_SCREEN+1) | ||
32 | #define MODE_AppKeyPad (MODES_SCREEN+2) | ||
33 | #define MODE_Mouse1000 (MODES_SCREEN+3) | ||
34 | #define MODE_Ansi (MODES_SCREEN+4) | ||
35 | #define MODE_total (MODES_SCREEN+5) | ||
36 | |||
37 | struct DECpar | ||
38 | { | ||
39 | BOOL mode[MODE_total]; | ||
40 | }; | ||
41 | |||
42 | struct CharCodes | ||
43 | { | ||
44 | // coding info | ||
45 | char charset[4]; // | ||
46 | int cu_cs; // actual charset. | ||
47 | bool graphic; // Some VT100 tricks | ||
48 | bool pound ; // Some VT100 tricks | ||
49 | bool sa_graphic; // saved graphic | ||
50 | bool sa_pound; // saved pound | ||
51 | }; | ||
52 | |||
53 | class TEmuVt102 : public TEmulation | ||
54 | { Q_OBJECT | ||
55 | |||
56 | public: | ||
57 | |||
58 | TEmuVt102(TEWidget* gui); | ||
59 | ~TEmuVt102(); | ||
60 | |||
61 | public slots: // signals incoming from TEWidget | ||
62 | |||
63 | void onKeyPress(QKeyEvent*); | ||
64 | void onMouse(int cb, int cx, int cy); | ||
65 | |||
66 | signals: | ||
67 | |||
68 | void changeTitle(int,const QString&); | ||
69 | void prevSession(); | ||
70 | void nextSession(); | ||
71 | |||
72 | public: | ||
73 | |||
74 | void reset(); | ||
75 | |||
76 | void onRcvChar(int cc); | ||
77 | void sendString(const char *); | ||
78 | |||
79 | public: | ||
80 | |||
81 | BOOL getMode (int m); | ||
82 | |||
83 | void setMode (int m); | ||
84 | void resetMode (int m); | ||
85 | void saveMode (int m); | ||
86 | void restoreMode(int m); | ||
87 | void resetModes(); | ||
88 | |||
89 | void setConnect(bool r); | ||
90 | |||
91 | private: | ||
92 | |||
93 | void resetToken(); | ||
94 | #define MAXPBUF 80 | ||
95 | void pushToToken(int cc); | ||
96 | int pbuf[MAXPBUF]; //FIXME: overflow? | ||
97 | int ppos; | ||
98 | #define MAXARGS 15 | ||
99 | void addDigit(int dig); | ||
100 | void addArgument(); | ||
101 | int argv[MAXARGS]; | ||
102 | int argc; | ||
103 | void initTokenizer(); | ||
104 | int tbl[256]; | ||
105 | |||
106 | void scan_buffer_report(); //FIXME: rename | ||
107 | void ReportErrorToken(); //FIXME: rename | ||
108 | |||
109 | void tau(int code, int p, int q); | ||
110 | void XtermHack(); | ||
111 | |||
112 | // | ||
113 | |||
114 | void reportTerminalType(); | ||
115 | void reportStatus(); | ||
116 | void reportAnswerBack(); | ||
117 | void reportCursorPosition(); | ||
118 | void reportTerminalParms(int p); | ||
119 | |||
120 | protected: | ||
121 | |||
122 | unsigned short applyCharset(unsigned short c); | ||
123 | void setCharset(int n, int cs); | ||
124 | void useCharset(int n); | ||
125 | void setAndUseCharset(int n, int cs); | ||
126 | void saveCursor(); | ||
127 | void restoreCursor(); | ||
128 | void resetCharset(int scrno); | ||
129 | CharCodes charset[2]; | ||
130 | |||
131 | DECpar currParm; | ||
132 | DECpar saveParm; | ||
133 | }; | ||
134 | |||
135 | #endif // ifndef ANSIEMU_H | ||
diff --git a/core/apps/embeddedkonsole/TEmulation.cpp b/core/apps/embeddedkonsole/TEmulation.cpp new file mode 100644 index 0000000..6f3ad32 --- a/dev/null +++ b/core/apps/embeddedkonsole/TEmulation.cpp | |||
@@ -0,0 +1,363 @@ | |||
1 | /* -------------------------------------------------------------------------- */ | ||
2 | /* */ | ||
3 | /* [TEmulation.cpp] Terminal Emulation Decoder */ | ||
4 | /* */ | ||
5 | /* -------------------------------------------------------------------------- */ | ||
6 | /* */ | ||
7 | /* Copyright (c) 1997,1998 by Lars Doelle <lars.doelle@on-line.de> */ | ||
8 | /* */ | ||
9 | /* This file is part of Konsole - an X terminal for KDE */ | ||
10 | /* */ | ||
11 | /* -------------------------------------------------------------------------- */ | ||
12 | /* */ | ||
13 | /* Ported Konsole to Qt/Embedded */ | ||
14 | /* */ | ||
15 | /* Copyright (C) 2000 by John Ryland <jryland@trolltech.com> */ | ||
16 | /* */ | ||
17 | /* -------------------------------------------------------------------------- */ | ||
18 | |||
19 | /*! \class TEmulation | ||
20 | |||
21 | \brief Mediator between TEWidget and TEScreen. | ||
22 | |||
23 | This class is responsible to scan the escapes sequences of the terminal | ||
24 | emulation and to map it to their corresponding semantic complements. | ||
25 | Thus this module knows mainly about decoding escapes sequences and | ||
26 | is a stateless device w.r.t. the semantics. | ||
27 | |||
28 | It is also responsible to refresh the TEWidget by certain rules. | ||
29 | |||
30 | \sa TEWidget \sa TEScreen | ||
31 | |||
32 | \par A note on refreshing | ||
33 | |||
34 | Although the modifications to the current screen image could immediately | ||
35 | be propagated via `TEWidget' to the graphical surface, we have chosen | ||
36 | another way here. | ||
37 | |||
38 | The reason for doing so is twofold. | ||
39 | |||
40 | First, experiments show that directly displaying the operation results | ||
41 | in slowing down the overall performance of emulations. Displaying | ||
42 | individual characters using X11 creates a lot of overhead. | ||
43 | |||
44 | Second, by using the following refreshing method, the screen operations | ||
45 | can be completely separated from the displaying. This greatly simplifies | ||
46 | the programmer's task of coding and maintaining the screen operations, | ||
47 | since one need not worry about differential modifications on the | ||
48 | display affecting the operation of concern. | ||
49 | |||
50 | We use a refreshing algorithm here that has been adoped from rxvt/kvt. | ||
51 | |||
52 | By this, refreshing is driven by a timer, which is (re)started whenever | ||
53 | a new bunch of data to be interpreted by the emulation arives at `onRcvBlock'. | ||
54 | As soon as no more data arrive for `BULK_TIMEOUT' milliseconds, we trigger | ||
55 | refresh. This rule suits both bulk display operation as done by curses as | ||
56 | well as individual characters typed. | ||
57 | (BULK_TIMEOUT < 1000 / max characters received from keyboard per second). | ||
58 | |||
59 | Additionally, we trigger refreshing by newlines comming in to make visual | ||
60 | snapshots of lists as produced by `cat', `ls' and likely programs, thereby | ||
61 | producing the illusion of a permanent and immediate display operation. | ||
62 | |||
63 | As a sort of catch-all needed for cases where none of the above | ||
64 | conditions catch, the screen refresh is also triggered by a count | ||
65 | of incoming bulks (`bulk_incnt'). | ||
66 | */ | ||
67 | |||
68 | /* FIXME | ||
69 | - evtl. the bulk operations could be made more transparent. | ||
70 | */ | ||
71 | |||
72 | #include "TEmulation.h" | ||
73 | #include "TEWidget.h" | ||
74 | #include "TEScreen.h" | ||
75 | #include <stdio.h> | ||
76 | #include <stdlib.h> | ||
77 | #include <unistd.h> | ||
78 | #include <qkeycode.h> | ||
79 | |||
80 | |||
81 | /* ------------------------------------------------------------------------- */ | ||
82 | /* */ | ||
83 | /* TEmulation */ | ||
84 | /* */ | ||
85 | /* ------------------------------------------------------------------------- */ | ||
86 | |||
87 | #define CNTL(c) ((c)-'@') | ||
88 | |||
89 | /*! | ||
90 | */ | ||
91 | |||
92 | TEmulation::TEmulation(TEWidget* gui) | ||
93 | : decoder((QTextDecoder*)NULL) | ||
94 | { | ||
95 | this->gui = gui; | ||
96 | |||
97 | screen[0] = new TEScreen(gui->Lines(),gui->Columns()); | ||
98 | screen[1] = new TEScreen(gui->Lines(),gui->Columns()); | ||
99 | scr = screen[0]; | ||
100 | |||
101 | bulk_nlcnt = 0; // reset bulk newline counter | ||
102 | bulk_incnt = 0; // reset bulk counter | ||
103 | connected = FALSE; | ||
104 | |||
105 | QObject::connect(&bulk_timer, SIGNAL(timeout()), this, SLOT(showBulk()) ); | ||
106 | QObject::connect(gui,SIGNAL(changedImageSizeSignal(int,int)), | ||
107 | this,SLOT(onImageSizeChange(int,int))); | ||
108 | QObject::connect(gui,SIGNAL(changedHistoryCursor(int)), | ||
109 | this,SLOT(onHistoryCursorChange(int))); | ||
110 | QObject::connect(gui,SIGNAL(keyPressedSignal(QKeyEvent*)), | ||
111 | this,SLOT(onKeyPress(QKeyEvent*))); | ||
112 | QObject::connect(gui,SIGNAL(beginSelectionSignal(const int,const int)), | ||
113 | this,SLOT(onSelectionBegin(const int,const int)) ); | ||
114 | QObject::connect(gui,SIGNAL(extendSelectionSignal(const int,const int)), | ||
115 | this,SLOT(onSelectionExtend(const int,const int)) ); | ||
116 | QObject::connect(gui,SIGNAL(endSelectionSignal(const BOOL)), | ||
117 | this,SLOT(setSelection(const BOOL)) ); | ||
118 | QObject::connect(gui,SIGNAL(clearSelectionSignal()), | ||
119 | this,SLOT(clearSelection()) ); | ||
120 | } | ||
121 | |||
122 | /*! | ||
123 | */ | ||
124 | |||
125 | TEmulation::~TEmulation() | ||
126 | { | ||
127 | delete screen[0]; | ||
128 | delete screen[1]; | ||
129 | bulk_timer.stop(); | ||
130 | } | ||
131 | |||
132 | /*! change between primary and alternate screen | ||
133 | */ | ||
134 | |||
135 | void TEmulation::setScreen(int n) | ||
136 | { | ||
137 | scr = screen[n&1]; | ||
138 | } | ||
139 | |||
140 | void TEmulation::setHistory(bool on) | ||
141 | { | ||
142 | screen[0]->setScroll(on); | ||
143 | if (!connected) return; | ||
144 | showBulk(); | ||
145 | } | ||
146 | |||
147 | bool TEmulation::history() | ||
148 | { | ||
149 | return screen[0]->hasScroll(); | ||
150 | } | ||
151 | |||
152 | void TEmulation::setCodec(int c) | ||
153 | { | ||
154 | //FIXME: check whether we have to free codec | ||
155 | codec = c ? QTextCodec::codecForName("utf8") | ||
156 | : QTextCodec::codecForLocale(); | ||
157 | if (decoder) delete decoder; | ||
158 | decoder = codec->makeDecoder(); | ||
159 | } | ||
160 | |||
161 | void TEmulation::setKeytrans(int no) | ||
162 | { | ||
163 | keytrans = KeyTrans::find(no); | ||
164 | } | ||
165 | |||
166 | void TEmulation::setKeytrans(const char * no) | ||
167 | { | ||
168 | keytrans = KeyTrans::find(no); | ||
169 | } | ||
170 | |||
171 | // Interpreting Codes --------------------------------------------------------- | ||
172 | |||
173 | /* | ||
174 | This section deals with decoding the incoming character stream. | ||
175 | Decoding means here, that the stream is first seperated into `tokens' | ||
176 | which are then mapped to a `meaning' provided as operations by the | ||
177 | `Screen' class. | ||
178 | */ | ||
179 | |||
180 | /*! | ||
181 | */ | ||
182 | |||
183 | void TEmulation::onRcvChar(int c) | ||
184 | // process application unicode input to terminal | ||
185 | // this is a trivial scanner | ||
186 | { | ||
187 | c &= 0xff; | ||
188 | switch (c) | ||
189 | { | ||
190 | case '\b' : scr->BackSpace(); break; | ||
191 | case '\t' : scr->Tabulate(); break; | ||
192 | case '\n' : scr->NewLine(); break; | ||
193 | case '\r' : scr->Return(); break; | ||
194 | case 0x07 : gui->Bell(); break; | ||
195 | default : scr->ShowCharacter(c); break; | ||
196 | }; | ||
197 | } | ||
198 | |||
199 | /* ------------------------------------------------------------------------- */ | ||
200 | /* */ | ||
201 | /* Keyboard Handling */ | ||
202 | /* */ | ||
203 | /* ------------------------------------------------------------------------- */ | ||
204 | |||
205 | /*! | ||
206 | */ | ||
207 | |||
208 | void TEmulation::onKeyPress( QKeyEvent* ev ) | ||
209 | { | ||
210 | if (!connected) return; // someone else gets the keys | ||
211 | if (scr->getHistCursor() != scr->getHistLines()); | ||
212 | scr->setHistCursor(scr->getHistLines()); | ||
213 | if (!ev->text().isEmpty()) | ||
214 | { // A block of text | ||
215 | // Note that the text is proper unicode. | ||
216 | // We should do a conversion here, but since this | ||
217 | // routine will never be used, we simply emit plain ascii. | ||
218 | emit sndBlock(ev->text().ascii(),ev->text().length()); | ||
219 | } | ||
220 | else if (ev->ascii()>0) | ||
221 | { unsigned char c[1]; | ||
222 | c[0] = ev->ascii(); | ||
223 | emit sndBlock((char*)c,1); | ||
224 | } | ||
225 | } | ||
226 | |||
227 | // Unblocking, Byte to Unicode translation --------------------------------- -- | ||
228 | |||
229 | /* | ||
230 | We are doing code conversion from locale to unicode first. | ||
231 | */ | ||
232 | |||
233 | void TEmulation::onRcvBlock(const char *s, int len) | ||
234 | { | ||
235 | bulkStart(); | ||
236 | bulk_incnt += 1; | ||
237 | for (int i = 0; i < len; i++) | ||
238 | { | ||
239 | QString result = decoder->toUnicode(&s[i],1); | ||
240 | int reslen = result.length(); | ||
241 | for (int j = 0; j < reslen; j++) | ||
242 | onRcvChar(result[j].unicode()); | ||
243 | if (s[i] == '\n') bulkNewline(); | ||
244 | } | ||
245 | bulkEnd(); | ||
246 | } | ||
247 | |||
248 | // Selection --------------------------------------------------------------- -- | ||
249 | |||
250 | void TEmulation::onSelectionBegin(const int x, const int y) { | ||
251 | if (!connected) return; | ||
252 | scr->setSelBeginXY(x,y); | ||
253 | showBulk(); | ||
254 | } | ||
255 | |||
256 | void TEmulation::onSelectionExtend(const int x, const int y) { | ||
257 | if (!connected) return; | ||
258 | scr->setSelExtentXY(x,y); | ||
259 | showBulk(); | ||
260 | } | ||
261 | |||
262 | void TEmulation::setSelection(const BOOL preserve_line_breaks) { | ||
263 | if (!connected) return; | ||
264 | QString t = scr->getSelText(preserve_line_breaks); | ||
265 | if (!t.isNull()) gui->setSelection(t); | ||
266 | } | ||
267 | |||
268 | void TEmulation::clearSelection() { | ||
269 | if (!connected) return; | ||
270 | scr->clearSelection(); | ||
271 | showBulk(); | ||
272 | } | ||
273 | |||
274 | // Refreshing -------------------------------------------------------------- -- | ||
275 | |||
276 | #define BULK_TIMEOUT 20 | ||
277 | |||
278 | /*! | ||
279 | called when \n comes in. Evtl. triggers showBulk at endBulk | ||
280 | */ | ||
281 | |||
282 | void TEmulation::bulkNewline() | ||
283 | { | ||
284 | bulk_nlcnt += 1; | ||
285 | bulk_incnt = 0; // reset bulk counter since `nl' rule applies | ||
286 | } | ||
287 | |||
288 | /*! | ||
289 | */ | ||
290 | |||
291 | void TEmulation::showBulk() | ||
292 | { | ||
293 | bulk_nlcnt = 0; // reset bulk newline counter | ||
294 | bulk_incnt = 0; // reset bulk counter | ||
295 | if (connected) | ||
296 | { | ||
297 | ca* image = scr->getCookedImage(); // get the image | ||
298 | gui->setImage(image, | ||
299 | scr->getLines(), | ||
300 | scr->getColumns()); // actual refresh | ||
301 | free(image); | ||
302 | //FIXME: check that we do not trigger other draw event here. | ||
303 | gui->setScroll(scr->getHistCursor(),scr->getHistLines()); | ||
304 | } | ||
305 | } | ||
306 | |||
307 | void TEmulation::bulkStart() | ||
308 | { | ||
309 | if (bulk_timer.isActive()) bulk_timer.stop(); | ||
310 | } | ||
311 | |||
312 | void TEmulation::bulkEnd() | ||
313 | { | ||
314 | if ( bulk_nlcnt > gui->Lines() || bulk_incnt > 20 ) | ||
315 | showBulk(); // resets bulk_??cnt to 0, too. | ||
316 | else | ||
317 | bulk_timer.start(BULK_TIMEOUT,TRUE); | ||
318 | } | ||
319 | |||
320 | void TEmulation::setConnect(bool c) | ||
321 | { | ||
322 | connected = c; | ||
323 | if ( connected) | ||
324 | { | ||
325 | onImageSizeChange(gui->Lines(), gui->Columns()); | ||
326 | showBulk(); | ||
327 | } | ||
328 | else | ||
329 | { | ||
330 | scr->clearSelection(); | ||
331 | } | ||
332 | } | ||
333 | |||
334 | // --------------------------------------------------------------------------- | ||
335 | |||
336 | /*! triggered by image size change of the TEWidget `gui'. | ||
337 | |||
338 | This event is simply propagated to the attached screens | ||
339 | and to the related serial line. | ||
340 | */ | ||
341 | |||
342 | void TEmulation::onImageSizeChange(int lines, int columns) | ||
343 | { | ||
344 | if (!connected) return; | ||
345 | screen[0]->resizeImage(lines,columns); | ||
346 | screen[1]->resizeImage(lines,columns); | ||
347 | showBulk(); | ||
348 | emit ImageSizeChanged(lines,columns); // propagate event to serial line | ||
349 | } | ||
350 | |||
351 | void TEmulation::onHistoryCursorChange(int cursor) | ||
352 | { | ||
353 | if (!connected) return; | ||
354 | scr->setHistCursor(cursor); | ||
355 | showBulk(); | ||
356 | } | ||
357 | |||
358 | void TEmulation::setColumns(int columns) | ||
359 | { | ||
360 | //FIXME: this goes strange ways. | ||
361 | // Can we put this straight or explain it at least? | ||
362 | emit changeColumns(columns); | ||
363 | } | ||
diff --git a/core/apps/embeddedkonsole/TEmulation.h b/core/apps/embeddedkonsole/TEmulation.h new file mode 100644 index 0000000..ec15e7a --- a/dev/null +++ b/core/apps/embeddedkonsole/TEmulation.h | |||
@@ -0,0 +1,117 @@ | |||
1 | /* -------------------------------------------------------------------------- */ | ||
2 | /* */ | ||
3 | /* [emulation.h] Fundamental Terminal Emulation */ | ||
4 | /* */ | ||
5 | /* -------------------------------------------------------------------------- */ | ||
6 | /* */ | ||
7 | /* Copyright (c) 1997,1998 by Lars Doelle <lars.doelle@on-line.de> */ | ||
8 | /* */ | ||
9 | /* This file is part of Konsole - an X terminal for KDE */ | ||
10 | /* */ | ||
11 | /* -------------------------------------------------------------------------- */ | ||
12 | /* */ | ||
13 | /* Ported Konsole to Qt/Embedded */ | ||
14 | /* */ | ||
15 | /* Copyright (C) 2000 by John Ryland <jryland@trolltech.com> */ | ||
16 | /* */ | ||
17 | /* -------------------------------------------------------------------------- */ | ||
18 | |||
19 | #ifndef EMULATION_H | ||
20 | #define EMULATION_H | ||
21 | |||
22 | #include "TEWidget.h" | ||
23 | #include "TEScreen.h" | ||
24 | #include <qtimer.h> | ||
25 | #include <stdio.h> | ||
26 | #include <qtextcodec.h> | ||
27 | #include "keytrans.h" | ||
28 | |||
29 | class TEmulation : public QObject | ||
30 | { Q_OBJECT | ||
31 | |||
32 | public: | ||
33 | |||
34 | TEmulation(TEWidget* gui); | ||
35 | ~TEmulation(); | ||
36 | |||
37 | public: | ||
38 | virtual void setHistory(bool on); | ||
39 | virtual bool history(); | ||
40 | |||
41 | public slots: // signals incoming from TEWidget | ||
42 | |||
43 | virtual void onImageSizeChange(int lines, int columns); | ||
44 | virtual void onHistoryCursorChange(int cursor); | ||
45 | virtual void onKeyPress(QKeyEvent*); | ||
46 | |||
47 | virtual void clearSelection(); | ||
48 | virtual void onSelectionBegin(const int x, const int y); | ||
49 | virtual void onSelectionExtend(const int x, const int y); | ||
50 | virtual void setSelection(const BOOL preserve_line_breaks); | ||
51 | |||
52 | public slots: // signals incoming from data source | ||
53 | |||
54 | void onRcvBlock(const char* txt,int len); | ||
55 | |||
56 | signals: | ||
57 | |||
58 | void sndBlock(const char* txt,int len); | ||
59 | void ImageSizeChanged(int lines, int columns); | ||
60 | void changeColumns(int columns); | ||
61 | void changeTitle(int arg, const char* str); | ||
62 | |||
63 | public: | ||
64 | |||
65 | virtual void onRcvChar(int); | ||
66 | |||
67 | virtual void setMode (int) = 0; | ||
68 | virtual void resetMode(int) = 0; | ||
69 | |||
70 | virtual void sendString(const char*) = 0; | ||
71 | |||
72 | virtual void setConnect(bool r); | ||
73 | void setColumns(int columns); | ||
74 | |||
75 | void setKeytrans(int no); | ||
76 | void setKeytrans(const char * no); | ||
77 | |||
78 | protected: | ||
79 | |||
80 | TEWidget* gui; | ||
81 | TEScreen* scr; // referes to one `screen' | ||
82 | TEScreen* screen[2]; // 0 = primary, 1 = alternate | ||
83 | void setScreen(int n); // set `scr' to `screen[n]' | ||
84 | |||
85 | bool connected; // communicate with widget | ||
86 | |||
87 | void setCodec(int c); // codec number, 0 = locale, 1=utf8 | ||
88 | |||
89 | QTextCodec* codec; | ||
90 | QTextCodec* localeCodec; | ||
91 | QTextDecoder* decoder; | ||
92 | |||
93 | KeyTrans* keytrans; | ||
94 | |||
95 | // refreshing related material. | ||
96 | // this is localized in the class. | ||
97 | private slots: // triggered by timer | ||
98 | |||
99 | void showBulk(); | ||
100 | |||
101 | private: | ||
102 | |||
103 | void bulkNewline(); | ||
104 | void bulkStart(); | ||
105 | void bulkEnd(); | ||
106 | |||
107 | private: | ||
108 | |||
109 | QTimer bulk_timer; | ||
110 | int bulk_nlcnt; // bulk newline counter | ||
111 | char* SelectedText; | ||
112 | int bulk_incnt; // bulk counter | ||
113 | |||
114 | |||
115 | }; | ||
116 | |||
117 | #endif // ifndef EMULATION_H | ||
diff --git a/core/apps/embeddedkonsole/default.keytab.h b/core/apps/embeddedkonsole/default.keytab.h new file mode 100644 index 0000000..503ea46 --- a/dev/null +++ b/core/apps/embeddedkonsole/default.keytab.h | |||
@@ -0,0 +1,103 @@ | |||
1 | /* generated by '../tests/quote ../other/default.Keytab' */ | ||
2 | |||
3 | "# [default.Keytab] Buildin Keyboard Table\n" | ||
4 | "\n" | ||
5 | "# --------------------------------------------------------------\n" | ||
6 | "#\n" | ||
7 | "# This file in included only for reference purposes. \n" | ||
8 | "#\n" | ||
9 | "# Modifying it does not have any effect (unless you\n" | ||
10 | "# derive the default.keytab.h and recompile konsole).\n" | ||
11 | "#\n" | ||
12 | "# To customize your keyboard, copy this file to something\n" | ||
13 | "# ending with .keytab and change it to meet you needs.\n" | ||
14 | "#\n" | ||
15 | "# --------------------------------------------------------------\n" | ||
16 | "\n" | ||
17 | "keyboard \"xterm (default)\"\n" | ||
18 | "\n" | ||
19 | "# --------------------------------------------------------------\n" | ||
20 | "#\n" | ||
21 | "# The syntax of each entry has the form\n" | ||
22 | "#\n" | ||
23 | "# \"key\" Keyname { (\"+\"|\"-\") Modename } \":\" (String|Operation)\n" | ||
24 | "#\n" | ||
25 | "# Keynames are those defined in <qnamespace.h>\n" | ||
26 | "# with the \"Qt::Key_\" prefix removed.\n" | ||
27 | "#\n" | ||
28 | "# Mode names are: Shift, Alt, Control.\n" | ||
29 | "#\n" | ||
30 | "# If the key is not found here, the text of the\n" | ||
31 | "# key event as provided by QT is emitted, possibly\n" | ||
32 | "# preceeded by ESC if the Alt key is pressed.\n" | ||
33 | "#\n" | ||
34 | "# --------------------------------------------------------------\n" | ||
35 | "#\n" | ||
36 | "# Note that this particular table is a \"risc\" version made to\n" | ||
37 | "# ease customization without bothering with obsolete details.\n" | ||
38 | "# See VT100.keytab for the more hairy stuff.\n" | ||
39 | "#\n" | ||
40 | "# --------------------------------------------------------------\n" | ||
41 | "\n" | ||
42 | "# common keys\n" | ||
43 | "\n" | ||
44 | "key Escape : \"\\E\"\n" | ||
45 | "key Tab : \"\\t\"\n" | ||
46 | "\n" | ||
47 | "key Return-Alt : \"\\r\"\n" | ||
48 | "key Return+Alt : \"\\E\\r\"\n" | ||
49 | "\n" | ||
50 | "# Backspace and Delete codes are preserving CTRL-H.\n" | ||
51 | "\n" | ||
52 | "key Backspace : \"\\x7f\"\n" | ||
53 | "\n" | ||
54 | "# cursor keys\n" | ||
55 | "\n" | ||
56 | "key Up -Shift : \"\\EOA\"\n" | ||
57 | "key Down -Shift : \"\\EOB\"\n" | ||
58 | "key Right -Shift : \"\\EOC\"\n" | ||
59 | "key Left -Shift : \"\\EOD\"\n" | ||
60 | "\n" | ||
61 | "# other grey PC keys\n" | ||
62 | "\n" | ||
63 | "key Enter : \"\\r\"\n" | ||
64 | "\n" | ||
65 | "key Home : \"\\E[1~\"\n" | ||
66 | "key Insert-Shift : \"\\E[2~\"\n" | ||
67 | "key Delete : \"\\E[3~\"\n" | ||
68 | "key End : \"\\E[4~\"\n" | ||
69 | "key Prior -Shift : \"\\E[5~\"\n" | ||
70 | "key Next -Shift : \"\\E[6~\"\n" | ||
71 | "\n" | ||
72 | "# function keys\n" | ||
73 | "\n" | ||
74 | "key F1 : \"\\E[11~\"\n" | ||
75 | "key F2 : \"\\E[12~\"\n" | ||
76 | "key F3 : \"\\E[13~\"\n" | ||
77 | "key F4 : \"\\E[14~\"\n" | ||
78 | "key F5 : \"\\E[15~\"\n" | ||
79 | "key F6 : \"\\E[17~\"\n" | ||
80 | "key F7 : \"\\E[18~\"\n" | ||
81 | "key F8 : \"\\E[19~\"\n" | ||
82 | "key F9 : \"\\E[20~\"\n" | ||
83 | "key F10 : \"\\E[21~\"\n" | ||
84 | "key F11 : \"\\E[23~\"\n" | ||
85 | "key F12 : \"\\E[24~\"\n" | ||
86 | "\n" | ||
87 | "# Work around dead keys\n" | ||
88 | "\n" | ||
89 | "key Space +Control : \"\\x00\"\n" | ||
90 | "\n" | ||
91 | "# Some keys are used by konsole to cause operations.\n" | ||
92 | "# The scroll* operations refer to the history buffer.\n" | ||
93 | "\n" | ||
94 | "key Left +Shift : prevSession\n" | ||
95 | "key Right +Shift : nextSession\n" | ||
96 | "key Up +Shift : scrollLineUp\n" | ||
97 | "key Prior +Shift : scrollPageUp\n" | ||
98 | "key Down +Shift : scrollLineDown\n" | ||
99 | "key Next +Shift : scrollPageDown\n" | ||
100 | "key Insert+Shift : emitSelection\n" | ||
101 | "\n" | ||
102 | "# keypad characters are not offered differently by Qt.\n" | ||
103 | "" | ||
diff --git a/core/apps/embeddedkonsole/embeddedkonsole.pro b/core/apps/embeddedkonsole/embeddedkonsole.pro new file mode 100755 index 0000000..b757ea5 --- a/dev/null +++ b/core/apps/embeddedkonsole/embeddedkonsole.pro | |||
@@ -0,0 +1,38 @@ | |||
1 | TEMPLATE= app | ||
2 | |||
3 | CONFIG += qt warn_on release | ||
4 | |||
5 | DESTDIR = $(QPEDIR)/bin | ||
6 | |||
7 | HEADERS = TEWidget.h \ | ||
8 | TEScreen.h \ | ||
9 | TECommon.h \ | ||
10 | TEHistory.h \ | ||
11 | TEmulation.h \ | ||
12 | TEmuVt102.h \ | ||
13 | session.h \ | ||
14 | keytrans.h \ | ||
15 | konsole.h \ | ||
16 | MyPty.h | ||
17 | |||
18 | SOURCES = TEScreen.cpp \ | ||
19 | TEWidget.cpp \ | ||
20 | TEHistory.cpp \ | ||
21 | TEmulation.cpp \ | ||
22 | TEmuVt102.cpp \ | ||
23 | session.cpp \ | ||
24 | keytrans.cpp \ | ||
25 | konsole.cpp \ | ||
26 | main.cpp \ | ||
27 | MyPty.cpp | ||
28 | |||
29 | TARGET = embeddedkonsole | ||
30 | |||
31 | INCLUDEPATH += $(QPEDIR)/include | ||
32 | |||
33 | DEPENDPATH+= $(QPEDIR)/include | ||
34 | |||
35 | LIBS += -lqpe | ||
36 | |||
37 | REQUIRES= embeddedkonsole | ||
38 | |||
diff --git a/core/apps/embeddedkonsole/faded_bg.png b/core/apps/embeddedkonsole/faded_bg.png new file mode 100644 index 0000000..7dbf6b4 --- a/dev/null +++ b/core/apps/embeddedkonsole/faded_bg.png | |||
Binary files differ | |||
diff --git a/core/apps/embeddedkonsole/keytrans.cpp b/core/apps/embeddedkonsole/keytrans.cpp new file mode 100644 index 0000000..d569ae0 --- a/dev/null +++ b/core/apps/embeddedkonsole/keytrans.cpp | |||
@@ -0,0 +1,706 @@ | |||
1 | /* -------------------------------------------------------------------------- */ | ||
2 | /* */ | ||
3 | /* [keytrans.C] Keyboard Translation */ | ||
4 | /* */ | ||
5 | /* -------------------------------------------------------------------------- */ | ||
6 | /* */ | ||
7 | /* Copyright (c) 1997,1998 by Lars Doelle <lars.doelle@on-line.de> */ | ||
8 | /* */ | ||
9 | /* This file is part of Konsole - an X terminal for KDE */ | ||
10 | /* */ | ||
11 | /* -------------------------------------------------------------------------- */ | ||
12 | /* */ | ||
13 | /* Ported Konsole to Qt/Embedded */ | ||
14 | /* */ | ||
15 | /* Copyright (C) 2000 by John Ryland <jryland@trolltech.com> */ | ||
16 | /* */ | ||
17 | /* -------------------------------------------------------------------------- */ | ||
18 | |||
19 | /* | ||
20 | The keyboard translation table allows to configure konsoles behavior | ||
21 | on key strokes. | ||
22 | |||
23 | FIXME: some bug crept in, disallowing '\0' to be emitted. | ||
24 | */ | ||
25 | |||
26 | #include "keytrans.h" | ||
27 | |||
28 | #include <qpe/qpeapplication.h> | ||
29 | |||
30 | #include <qnamespace.h> | ||
31 | #include <qbuffer.h> | ||
32 | #include <qobject.h> | ||
33 | #include <qdict.h> | ||
34 | #include <qintdict.h> | ||
35 | #include <qfile.h> | ||
36 | #include <qglobal.h> | ||
37 | #include <qdir.h> | ||
38 | |||
39 | //#include <kstddirs.h> | ||
40 | //nclude <klocale.h> | ||
41 | |||
42 | #include <stdio.h> | ||
43 | |||
44 | |||
45 | #undef USE_APPDATA_DIR | ||
46 | |||
47 | |||
48 | #define HERE printf("%s(%d): here\n",__FILE__,__LINE__) | ||
49 | |||
50 | /* KeyEntry | ||
51 | |||
52 | instances represent the individual assignments | ||
53 | */ | ||
54 | |||
55 | KeyTrans::KeyEntry::KeyEntry(int _ref, int _key, int _bits, int _mask, int _cmd, QString _txt) | ||
56 | : ref(_ref), key(_key), bits(_bits), mask(_mask), cmd(_cmd), txt(_txt) | ||
57 | { | ||
58 | } | ||
59 | |||
60 | KeyTrans::KeyEntry::~KeyEntry() | ||
61 | { | ||
62 | } | ||
63 | |||
64 | bool KeyTrans::KeyEntry::matches(int _key, int _bits, int _mask) | ||
65 | { int m = mask & _mask; | ||
66 | return _key == key && (bits & m) == (_bits & m); | ||
67 | } | ||
68 | |||
69 | QString KeyTrans::KeyEntry::text() | ||
70 | { | ||
71 | return txt; | ||
72 | } | ||
73 | |||
74 | /* KeyTrans | ||
75 | |||
76 | combines the individual assignments to a proper map | ||
77 | Takes part in a collection themself. | ||
78 | */ | ||
79 | |||
80 | KeyTrans::KeyTrans() | ||
81 | { | ||
82 | path = ""; | ||
83 | numb = 0; | ||
84 | } | ||
85 | |||
86 | KeyTrans::~KeyTrans() | ||
87 | { | ||
88 | } | ||
89 | |||
90 | KeyTrans::KeyEntry* KeyTrans::addEntry(int ref, int key, int bits, int mask, int cmd, QString txt) | ||
91 | // returns conflicting entry | ||
92 | { | ||
93 | for (QListIterator<KeyEntry> it(table); it.current(); ++it) | ||
94 | { | ||
95 | if (it.current()->matches(key,bits,mask)) | ||
96 | { | ||
97 | return it.current(); | ||
98 | } | ||
99 | } | ||
100 | table.append(new KeyEntry(ref,key,bits,mask,cmd,txt)); | ||
101 | return (KeyEntry*)NULL; | ||
102 | } | ||
103 | |||
104 | bool KeyTrans::findEntry(int key, int bits, int* cmd, const char** txt, int* len) | ||
105 | { | ||
106 | for (QListIterator<KeyEntry> it(table); it.current(); ++it) | ||
107 | if (it.current()->matches(key,bits,0xffff)) | ||
108 | { | ||
109 | *cmd = it.current()->cmd; | ||
110 | *txt = it.current()->txt.ascii(); | ||
111 | *len = it.current()->txt.length(); | ||
112 | return TRUE; | ||
113 | } | ||
114 | return FALSE; | ||
115 | } | ||
116 | |||
117 | /* ------------------------------------------------------------------------- */ | ||
118 | /* */ | ||
119 | /* Scanner for keyboard configuration */ | ||
120 | /* */ | ||
121 | /* ------------------------------------------------------------------------- */ | ||
122 | |||
123 | // regular tokenizer | ||
124 | /* Tokens | ||
125 | - Spaces | ||
126 | - Name (A-Za-z0-9)+ | ||
127 | - String | ||
128 | - Opr on of +-: | ||
129 | */ | ||
130 | |||
131 | #define SYMName 0 | ||
132 | #define SYMString 1 | ||
133 | #define SYMEol 2 | ||
134 | #define SYMEof 3 | ||
135 | #define SYMOpr 4 | ||
136 | #define SYMError 5 | ||
137 | |||
138 | #define inRange(L,X,H) ((L <= X) && (X <= H)) | ||
139 | #define isNibble(X) (inRange('A',X,'F')||inRange('a',X,'f')||inRange('0',X,'9')) | ||
140 | #define convNibble(X) (inRange('0',X,'9')?X-'0':X+10-(inRange('A',X,'F')?'A':'a')) | ||
141 | |||
142 | class KeytabReader | ||
143 | { | ||
144 | public: | ||
145 | KeytabReader(QString p, QIODevice &d); | ||
146 | public: | ||
147 | void getCc(); | ||
148 | void getSymbol(); | ||
149 | void parseTo(KeyTrans* kt); | ||
150 | void ReportError(const char* msg); | ||
151 | void ReportToken(); // diagnostic | ||
152 | private: | ||
153 | int sym; | ||
154 | QString res; | ||
155 | int len; | ||
156 | int slinno; | ||
157 | int scolno; | ||
158 | private: | ||
159 | int cc; | ||
160 | int linno; | ||
161 | int colno; | ||
162 | QIODevice* buf; | ||
163 | QString path; | ||
164 | }; | ||
165 | |||
166 | |||
167 | KeytabReader::KeytabReader(QString p, QIODevice &d) | ||
168 | { | ||
169 | path = p; | ||
170 | buf = &d; | ||
171 | cc = 0; | ||
172 | } | ||
173 | |||
174 | void KeytabReader::getCc() | ||
175 | { | ||
176 | if (cc == '\n') { linno += 1; colno = 0; } | ||
177 | if (cc < 0) return; | ||
178 | cc = buf->getch(); | ||
179 | colno += 1; | ||
180 | } | ||
181 | |||
182 | void KeytabReader::getSymbol() | ||
183 | { | ||
184 | res = ""; len = 0; sym = SYMError; | ||
185 | while (cc == ' ') getCc(); // skip spaces | ||
186 | if (cc == '#') // skip comment | ||
187 | { | ||
188 | while (cc != '\n' && cc > 0) getCc(); | ||
189 | } | ||
190 | slinno = linno; | ||
191 | scolno = colno; | ||
192 | if (cc <= 0) | ||
193 | { | ||
194 | sym = SYMEof; return; // eos | ||
195 | } | ||
196 | if (cc == '\n') | ||
197 | { | ||
198 | getCc(); | ||
199 | sym = SYMEol; return; // eol | ||
200 | } | ||
201 | if (inRange('A',cc,'Z')||inRange('a',cc,'z')||inRange('0',cc,'9')) | ||
202 | { | ||
203 | while (inRange('A',cc,'Z') || inRange('a',cc,'z') || inRange('0',cc,'9')) | ||
204 | { | ||
205 | res = res + (char)cc; | ||
206 | getCc(); | ||
207 | } | ||
208 | sym = SYMName; | ||
209 | return; | ||
210 | } | ||
211 | if (strchr("+-:",cc)) | ||
212 | { | ||
213 | res = ""; | ||
214 | res = res + (char)cc; | ||
215 | getCc(); | ||
216 | sym = SYMOpr; return; | ||
217 | } | ||
218 | if (cc == '"') | ||
219 | { | ||
220 | getCc(); | ||
221 | while (cc >= ' ' && cc != '"') | ||
222 | { int sc; | ||
223 | if (cc == '\\') // handle quotation | ||
224 | { | ||
225 | getCc(); | ||
226 | switch (cc) | ||
227 | { | ||
228 | case 'E' : sc = 27; getCc(); break; | ||
229 | case 'b' : sc = 8; getCc(); break; | ||
230 | case 'f' : sc = 12; getCc(); break; | ||
231 | case 't' : sc = 9; getCc(); break; | ||
232 | case 'r' : sc = 13; getCc(); break; | ||
233 | case 'n' : sc = 10; getCc(); break; | ||
234 | case '\\' : // fall thru | ||
235 | case '"' : sc = cc; getCc(); break; | ||
236 | case 'x' : getCc(); | ||
237 | sc = 0; | ||
238 | if (!isNibble(cc)) return; sc = 16*sc + convNibble(cc); getCc(); | ||
239 | if (!isNibble(cc)) return; sc = 16*sc + convNibble(cc); getCc(); | ||
240 | break; | ||
241 | default : return; | ||
242 | } | ||
243 | } | ||
244 | else | ||
245 | { | ||
246 | // regular char | ||
247 | sc = cc; getCc(); | ||
248 | } | ||
249 | res = res + (char)sc; | ||
250 | len = len + 1; | ||
251 | } | ||
252 | if (cc != '"') return; | ||
253 | getCc(); | ||
254 | sym = SYMString; return; | ||
255 | } | ||
256 | } | ||
257 | |||
258 | void KeytabReader::ReportToken() // diagnostic | ||
259 | { | ||
260 | printf("sym(%d): ",slinno); | ||
261 | switch(sym) | ||
262 | { | ||
263 | case SYMEol : printf("End of line"); break; | ||
264 | case SYMEof : printf("End of file"); break; | ||
265 | case SYMName : printf("Name: %s",res.latin1()); break; | ||
266 | case SYMOpr : printf("Opr : %s",res.latin1()); break; | ||
267 | case SYMString : printf("String len %d,%d ",res.length(),len); | ||
268 | for (unsigned i = 0; i < res.length(); i++) | ||
269 | printf(" %02x(%c)",res.latin1()[i],res.latin1()[i]>=' '?res.latin1()[i]:'?'); | ||
270 | break; | ||
271 | } | ||
272 | printf("\n"); | ||
273 | } | ||
274 | |||
275 | void KeytabReader::ReportError(const char* msg) // diagnostic | ||
276 | { | ||
277 | fprintf(stderr,"%s(%d,%d):error: %s.\n",path.ascii(),slinno,scolno,msg); | ||
278 | } | ||
279 | |||
280 | // local symbol tables --------------------------------------------------------------------- | ||
281 | |||
282 | class KeyTransSymbols | ||
283 | { | ||
284 | public: | ||
285 | KeyTransSymbols(); | ||
286 | protected: | ||
287 | void defOprSyms(); | ||
288 | void defModSyms(); | ||
289 | void defKeySyms(); | ||
290 | void defKeySym(const char* key, int val); | ||
291 | void defOprSym(const char* key, int val); | ||
292 | void defModSym(const char* key, int val); | ||
293 | public: | ||
294 | QDict<QObject> keysyms; | ||
295 | QDict<QObject> modsyms; | ||
296 | QDict<QObject> oprsyms; | ||
297 | }; | ||
298 | |||
299 | static KeyTransSymbols * syms = 0L; | ||
300 | |||
301 | // parser ---------------------------------------------------------------------------------- | ||
302 | /* Syntax | ||
303 | - Line :: [KeyName { ("+" | "-") ModeName } ":" (String|CommandName)] "\n" | ||
304 | - Comment :: '#' (any but \n)* | ||
305 | */ | ||
306 | |||
307 | KeyTrans* KeyTrans::fromDevice(QString path, QIODevice &buf) | ||
308 | { | ||
309 | KeyTrans* kt = new KeyTrans; | ||
310 | kt->path = path; | ||
311 | KeytabReader ktr(path,buf); ktr.parseTo(kt); | ||
312 | return kt; | ||
313 | } | ||
314 | |||
315 | |||
316 | #define assertSyntax(Cond,Message) if (!(Cond)) { ReportError(Message); goto ERROR; } | ||
317 | |||
318 | void KeytabReader::parseTo(KeyTrans* kt) | ||
319 | { | ||
320 | // Opening sequence | ||
321 | |||
322 | buf->open(IO_ReadOnly); | ||
323 | getCc(); | ||
324 | linno = 1; | ||
325 | colno = 1; | ||
326 | getSymbol(); | ||
327 | |||
328 | Loop: | ||
329 | // syntax: ["key" KeyName { ("+" | "-") ModeName } ":" String/CommandName] ["#" Comment] | ||
330 | if (sym == SYMName && !strcmp(res.latin1(),"keyboard")) | ||
331 | { | ||
332 | getSymbol(); assertSyntax(sym == SYMString, "Header expected") | ||
333 | kt->hdr = res.latin1(); | ||
334 | getSymbol(); assertSyntax(sym == SYMEol, "Text unexpected") | ||
335 | getSymbol(); // eoln | ||
336 | goto Loop; | ||
337 | } | ||
338 | if (sym == SYMName && !strcmp(res.latin1(),"key")) | ||
339 | { | ||
340 | //printf("line %3d: ",startofsym); | ||
341 | getSymbol(); assertSyntax(sym == SYMName, "Name expected") | ||
342 | assertSyntax(syms->keysyms[res], "Unknown key name") | ||
343 | int key = (int)syms->keysyms[res]-1; | ||
344 | //printf(" key %s (%04x)",res.latin1(),(int)syms->keysyms[res]-1); | ||
345 | getSymbol(); // + - : | ||
346 | int mode = 0; | ||
347 | int mask = 0; | ||
348 | while (sym == SYMOpr && (!strcmp(res.latin1(),"+") || !strcmp(res.latin1(),"-"))) | ||
349 | { | ||
350 | bool on = !strcmp(res.latin1(),"+"); | ||
351 | getSymbol(); | ||
352 | // mode name | ||
353 | assertSyntax(sym == SYMName, "Name expected") | ||
354 | assertSyntax(syms->modsyms[res], "Unknown mode name") | ||
355 | int bits = (int)syms->modsyms[res]-1; | ||
356 | if (mask & (1 << bits)) | ||
357 | { | ||
358 | fprintf(stderr,"%s(%d,%d): mode name used multible times.\n",path.ascii(),slinno,scolno); | ||
359 | } | ||
360 | else | ||
361 | { | ||
362 | mode |= (on << bits); | ||
363 | mask |= (1 << bits); | ||
364 | } | ||
365 | //printf(", mode %s(%d) %s",res.latin1(),(int)syms->modsyms[res]-1,on?"on":"off"); | ||
366 | getSymbol(); | ||
367 | } | ||
368 | assertSyntax(sym == SYMOpr && !strcmp(res.latin1(),":"), "':' expected") | ||
369 | getSymbol(); | ||
370 | // string or command | ||
371 | assertSyntax(sym == SYMName || sym == SYMString,"Command or string expected") | ||
372 | int cmd = 0; | ||
373 | if (sym == SYMName) | ||
374 | { | ||
375 | assertSyntax(syms->oprsyms[res], "Unknown operator name") | ||
376 | cmd = (int)syms->oprsyms[res]-1; | ||
377 | //printf(": do %s(%d)",res.latin1(),(int)syms->oprsyms[res]-1); | ||
378 | } | ||
379 | if (sym == SYMString) | ||
380 | { | ||
381 | cmd = CMD_send; | ||
382 | //printf(": send"); | ||
383 | //for (unsigned i = 0; i < res.length(); i++) | ||
384 | //printf(" %02x(%c)",res.latin1()[i],res.latin1()[i]>=' '?res.latin1()[i]:'?'); | ||
385 | } | ||
386 | //printf(". summary %04x,%02x,%02x,%d\n",key,mode,mask,cmd); | ||
387 | KeyTrans::KeyEntry* ke = kt->addEntry(slinno,key,mode,mask,cmd,res); | ||
388 | if (ke) | ||
389 | { | ||
390 | fprintf(stderr,"%s(%d): keystroke already assigned in line %d.\n",path.ascii(),slinno,ke->ref); | ||
391 | } | ||
392 | getSymbol(); | ||
393 | assertSyntax(sym == SYMEol, "Unexpected text") | ||
394 | goto Loop; | ||
395 | } | ||
396 | if (sym == SYMEol) | ||
397 | { | ||
398 | getSymbol(); | ||
399 | goto Loop; | ||
400 | } | ||
401 | |||
402 | assertSyntax(sym == SYMEof, "Undecodable Line") | ||
403 | |||
404 | buf->close(); | ||
405 | return; | ||
406 | |||
407 | ERROR: | ||
408 | while (sym != SYMEol && sym != SYMEof) getSymbol(); // eoln | ||
409 | goto Loop; | ||
410 | } | ||
411 | |||
412 | |||
413 | KeyTrans* KeyTrans::defaultKeyTrans() | ||
414 | { | ||
415 | QCString txt = | ||
416 | #include "default.keytab.h" | ||
417 | ; | ||
418 | QBuffer buf(txt); | ||
419 | return fromDevice("[buildin]",buf); | ||
420 | } | ||
421 | |||
422 | KeyTrans* KeyTrans::fromFile(const char* path) | ||
423 | { | ||
424 | QFile file(path); | ||
425 | return fromDevice(path,file); | ||
426 | } | ||
427 | |||
428 | // local symbol tables --------------------------------------------------------------------- | ||
429 | // material needed for parsing the config file. | ||
430 | // This is incomplete work. | ||
431 | |||
432 | void KeyTransSymbols::defKeySym(const char* key, int val) | ||
433 | { | ||
434 | keysyms.insert(key,(QObject*)(val+1)); | ||
435 | } | ||
436 | |||
437 | void KeyTransSymbols::defOprSym(const char* key, int val) | ||
438 | { | ||
439 | oprsyms.insert(key,(QObject*)(val+1)); | ||
440 | } | ||
441 | |||
442 | void KeyTransSymbols::defModSym(const char* key, int val) | ||
443 | { | ||
444 | modsyms.insert(key,(QObject*)(val+1)); | ||
445 | } | ||
446 | |||
447 | void KeyTransSymbols::defOprSyms() | ||
448 | { | ||
449 | // Modifier | ||
450 | defOprSym("scrollLineUp", CMD_scrollLineUp ); | ||
451 | defOprSym("scrollLineDown",CMD_scrollLineDown); | ||
452 | defOprSym("scrollPageUp", CMD_scrollPageUp ); | ||
453 | defOprSym("scrollPageDown",CMD_scrollPageDown); | ||
454 | defOprSym("emitSelection", CMD_emitSelection ); | ||
455 | defOprSym("prevSession", CMD_prevSession ); | ||
456 | defOprSym("nextSession", CMD_nextSession ); | ||
457 | } | ||
458 | |||
459 | void KeyTransSymbols::defModSyms() | ||
460 | { | ||
461 | // Modifier | ||
462 | defModSym("Shift", BITS_Shift ); | ||
463 | defModSym("Control", BITS_Control ); | ||
464 | defModSym("Alt", BITS_Alt ); | ||
465 | // Modes | ||
466 | defModSym("BsHack", BITS_BsHack ); // deprecated | ||
467 | defModSym("Ansi", BITS_Ansi ); | ||
468 | defModSym("NewLine", BITS_NewLine ); | ||
469 | defModSym("AppCuKeys", BITS_AppCuKeys ); | ||
470 | } | ||
471 | |||
472 | void KeyTransSymbols::defKeySyms() | ||
473 | { | ||
474 | // Grey keys | ||
475 | defKeySym("Escape", Qt::Key_Escape ); | ||
476 | defKeySym("Tab", Qt::Key_Tab ); | ||
477 | defKeySym("Backtab", Qt::Key_Backtab ); | ||
478 | defKeySym("Backspace", Qt::Key_Backspace ); | ||
479 | defKeySym("Return", Qt::Key_Return ); | ||
480 | defKeySym("Enter", Qt::Key_Enter ); | ||
481 | defKeySym("Insert", Qt::Key_Insert ); | ||
482 | defKeySym("Delete", Qt::Key_Delete ); | ||
483 | defKeySym("Pause", Qt::Key_Pause ); | ||
484 | defKeySym("Print", Qt::Key_Print ); | ||
485 | defKeySym("SysReq", Qt::Key_SysReq ); | ||
486 | defKeySym("Home", Qt::Key_Home ); | ||
487 | defKeySym("End", Qt::Key_End ); | ||
488 | defKeySym("Left", Qt::Key_Left ); | ||
489 | defKeySym("Up", Qt::Key_Up ); | ||
490 | defKeySym("Right", Qt::Key_Right ); | ||
491 | defKeySym("Down", Qt::Key_Down ); | ||
492 | defKeySym("Prior", Qt::Key_Prior ); | ||
493 | defKeySym("Next", Qt::Key_Next ); | ||
494 | defKeySym("Shift", Qt::Key_Shift ); | ||
495 | defKeySym("Control", Qt::Key_Control ); | ||
496 | defKeySym("Meta", Qt::Key_Meta ); | ||
497 | defKeySym("Alt", Qt::Key_Alt ); | ||
498 | defKeySym("CapsLock", Qt::Key_CapsLock ); | ||
499 | defKeySym("NumLock", Qt::Key_NumLock ); | ||
500 | defKeySym("ScrollLock", Qt::Key_ScrollLock ); | ||
501 | defKeySym("F1", Qt::Key_F1 ); | ||
502 | defKeySym("F2", Qt::Key_F2 ); | ||
503 | defKeySym("F3", Qt::Key_F3 ); | ||
504 | defKeySym("F4", Qt::Key_F4 ); | ||
505 | defKeySym("F5", Qt::Key_F5 ); | ||
506 | defKeySym("F6", Qt::Key_F6 ); | ||
507 | defKeySym("F7", Qt::Key_F7 ); | ||
508 | defKeySym("F8", Qt::Key_F8 ); | ||
509 | defKeySym("F9", Qt::Key_F9 ); | ||
510 | defKeySym("F10", Qt::Key_F10 ); | ||
511 | defKeySym("F11", Qt::Key_F11 ); | ||
512 | defKeySym("F12", Qt::Key_F12 ); | ||
513 | defKeySym("F13", Qt::Key_F13 ); | ||
514 | defKeySym("F14", Qt::Key_F14 ); | ||
515 | defKeySym("F15", Qt::Key_F15 ); | ||
516 | defKeySym("F16", Qt::Key_F16 ); | ||
517 | defKeySym("F17", Qt::Key_F17 ); | ||
518 | defKeySym("F18", Qt::Key_F18 ); | ||
519 | defKeySym("F19", Qt::Key_F19 ); | ||
520 | defKeySym("F20", Qt::Key_F20 ); | ||
521 | defKeySym("F21", Qt::Key_F21 ); | ||
522 | defKeySym("F22", Qt::Key_F22 ); | ||
523 | defKeySym("F23", Qt::Key_F23 ); | ||
524 | defKeySym("F24", Qt::Key_F24 ); | ||
525 | defKeySym("F25", Qt::Key_F25 ); | ||
526 | defKeySym("F26", Qt::Key_F26 ); | ||
527 | defKeySym("F27", Qt::Key_F27 ); | ||
528 | defKeySym("F28", Qt::Key_F28 ); | ||
529 | defKeySym("F29", Qt::Key_F29 ); | ||
530 | defKeySym("F30", Qt::Key_F30 ); | ||
531 | defKeySym("F31", Qt::Key_F31 ); | ||
532 | defKeySym("F32", Qt::Key_F32 ); | ||
533 | defKeySym("F33", Qt::Key_F33 ); | ||
534 | defKeySym("F34", Qt::Key_F34 ); | ||
535 | defKeySym("F35", Qt::Key_F35 ); | ||
536 | defKeySym("Super_L", Qt::Key_Super_L ); | ||
537 | defKeySym("Super_R", Qt::Key_Super_R ); | ||
538 | defKeySym("Menu", Qt::Key_Menu ); | ||
539 | defKeySym("Hyper_L", Qt::Key_Hyper_L ); | ||
540 | defKeySym("Hyper_R", Qt::Key_Hyper_R ); | ||
541 | |||
542 | // Regular keys | ||
543 | defKeySym("Space", Qt::Key_Space ); | ||
544 | defKeySym("Exclam", Qt::Key_Exclam ); | ||
545 | defKeySym("QuoteDbl", Qt::Key_QuoteDbl ); | ||
546 | defKeySym("NumberSign", Qt::Key_NumberSign ); | ||
547 | defKeySym("Dollar", Qt::Key_Dollar ); | ||
548 | defKeySym("Percent", Qt::Key_Percent ); | ||
549 | defKeySym("Ampersand", Qt::Key_Ampersand ); | ||
550 | defKeySym("Apostrophe", Qt::Key_Apostrophe ); | ||
551 | defKeySym("ParenLeft", Qt::Key_ParenLeft ); | ||
552 | defKeySym("ParenRight", Qt::Key_ParenRight ); | ||
553 | defKeySym("Asterisk", Qt::Key_Asterisk ); | ||
554 | defKeySym("Plus", Qt::Key_Plus ); | ||
555 | defKeySym("Comma", Qt::Key_Comma ); | ||
556 | defKeySym("Minus", Qt::Key_Minus ); | ||
557 | defKeySym("Period", Qt::Key_Period ); | ||
558 | defKeySym("Slash", Qt::Key_Slash ); | ||
559 | defKeySym("0", Qt::Key_0 ); | ||
560 | defKeySym("1", Qt::Key_1 ); | ||
561 | defKeySym("2", Qt::Key_2 ); | ||
562 | defKeySym("3", Qt::Key_3 ); | ||
563 | defKeySym("4", Qt::Key_4 ); | ||
564 | defKeySym("5", Qt::Key_5 ); | ||
565 | defKeySym("6", Qt::Key_6 ); | ||
566 | defKeySym("7", Qt::Key_7 ); | ||
567 | defKeySym("8", Qt::Key_8 ); | ||
568 | defKeySym("9", Qt::Key_9 ); | ||
569 | defKeySym("Colon", Qt::Key_Colon ); | ||
570 | defKeySym("Semicolon", Qt::Key_Semicolon ); | ||
571 | defKeySym("Less", Qt::Key_Less ); | ||
572 | defKeySym("Equal", Qt::Key_Equal ); | ||
573 | defKeySym("Greater", Qt::Key_Greater ); | ||
574 | defKeySym("Question", Qt::Key_Question ); | ||
575 | defKeySym("At", Qt::Key_At ); | ||
576 | defKeySym("A", Qt::Key_A ); | ||
577 | defKeySym("B", Qt::Key_B ); | ||
578 | defKeySym("C", Qt::Key_C ); | ||
579 | defKeySym("D", Qt::Key_D ); | ||
580 | defKeySym("E", Qt::Key_E ); | ||
581 | defKeySym("F", Qt::Key_F ); | ||
582 | defKeySym("G", Qt::Key_G ); | ||
583 | defKeySym("H", Qt::Key_H ); | ||
584 | defKeySym("I", Qt::Key_I ); | ||
585 | defKeySym("J", Qt::Key_J ); | ||
586 | defKeySym("K", Qt::Key_K ); | ||
587 | defKeySym("L", Qt::Key_L ); | ||
588 | defKeySym("M", Qt::Key_M ); | ||
589 | defKeySym("N", Qt::Key_N ); | ||
590 | defKeySym("O", Qt::Key_O ); | ||
591 | defKeySym("P", Qt::Key_P ); | ||
592 | defKeySym("Q", Qt::Key_Q ); | ||
593 | defKeySym("R", Qt::Key_R ); | ||
594 | defKeySym("S", Qt::Key_S ); | ||
595 | defKeySym("T", Qt::Key_T ); | ||
596 | defKeySym("U", Qt::Key_U ); | ||
597 | defKeySym("V", Qt::Key_V ); | ||
598 | defKeySym("W", Qt::Key_W ); | ||
599 | defKeySym("X", Qt::Key_X ); | ||
600 | defKeySym("Y", Qt::Key_Y ); | ||
601 | defKeySym("Z", Qt::Key_Z ); | ||
602 | defKeySym("BracketLeft", Qt::Key_BracketLeft ); | ||
603 | defKeySym("Backslash", Qt::Key_Backslash ); | ||
604 | defKeySym("BracketRight", Qt::Key_BracketRight); | ||
605 | defKeySym("AsciiCircum", Qt::Key_AsciiCircum ); | ||
606 | defKeySym("Underscore", Qt::Key_Underscore ); | ||
607 | defKeySym("QuoteLeft", Qt::Key_QuoteLeft ); | ||
608 | defKeySym("BraceLeft", Qt::Key_BraceLeft ); | ||
609 | defKeySym("Bar", Qt::Key_Bar ); | ||
610 | defKeySym("BraceRight", Qt::Key_BraceRight ); | ||
611 | defKeySym("AsciiTilde", Qt::Key_AsciiTilde ); | ||
612 | } | ||
613 | |||
614 | KeyTransSymbols::KeyTransSymbols() | ||
615 | { | ||
616 | defModSyms(); | ||
617 | defOprSyms(); | ||
618 | defKeySyms(); | ||
619 | } | ||
620 | |||
621 | // Global material ----------------------------------------------------------- | ||
622 | |||
623 | static int keytab_serial = 0; //FIXME: remove,localize | ||
624 | |||
625 | static QIntDict<KeyTrans> * numb2keymap = 0L; | ||
626 | static QDict<KeyTrans> * path2keymap = 0L; | ||
627 | |||
628 | KeyTrans* KeyTrans::find(int numb) | ||
629 | { | ||
630 | KeyTrans* res = numb2keymap->find(numb); | ||
631 | return res ? res : numb2keymap->find(0); | ||
632 | } | ||
633 | |||
634 | KeyTrans* KeyTrans::find(const char* path) | ||
635 | { | ||
636 | KeyTrans* res = path2keymap->find(path); | ||
637 | return res ? res : numb2keymap->find(0); | ||
638 | } | ||
639 | |||
640 | int KeyTrans::count() | ||
641 | { | ||
642 | return numb2keymap->count(); | ||
643 | } | ||
644 | |||
645 | void KeyTrans::addKeyTrans() | ||
646 | { | ||
647 | this->numb = keytab_serial ++; | ||
648 | numb2keymap->insert(numb,this); | ||
649 | path2keymap->insert(path,this); | ||
650 | } | ||
651 | |||
652 | void KeyTrans::loadAll() | ||
653 | { | ||
654 | if (!numb2keymap) | ||
655 | numb2keymap = new QIntDict<KeyTrans>; | ||
656 | if (!path2keymap) | ||
657 | path2keymap = new QDict<KeyTrans>; | ||
658 | if (!syms) | ||
659 | syms = new KeyTransSymbols; | ||
660 | |||
661 | defaultKeyTrans()->addKeyTrans(); | ||
662 | |||
663 | |||
664 | QString path = QPEApplication::qpeDir() + "etc/keytabs"; | ||
665 | QDir dir(path); | ||
666 | QStringList lst = dir.entryList("*.keytab"); | ||
667 | |||
668 | for(QStringList::Iterator it = lst.begin(); it != lst.end(); ++it ) { | ||
669 | QFile file(path + "/" + *it); | ||
670 | KeyTrans* sc = KeyTrans::fromDevice(*it, file); | ||
671 | if (sc) { | ||
672 | sc->addKeyTrans(); | ||
673 | } | ||
674 | } | ||
675 | |||
676 | } | ||
677 | |||
678 | // Debugging material ----------------------------------------------------------- | ||
679 | /* | ||
680 | void TestTokenizer(QBuffer &buf) | ||
681 | { | ||
682 | // opening sequence | ||
683 | |||
684 | buf.open(IO_ReadOnly); | ||
685 | cc = buf.getch(); | ||
686 | lineno = 1; | ||
687 | |||
688 | // Test tokenizer | ||
689 | |||
690 | while (getSymbol(buf)) ReportToken(); | ||
691 | |||
692 | buf.close(); | ||
693 | } | ||
694 | |||
695 | void test() | ||
696 | { | ||
697 | // Opening sequence | ||
698 | |||
699 | QCString txt = | ||
700 | #include "default.keytab.h" | ||
701 | ; | ||
702 | QBuffer buf(txt); | ||
703 | if (0) TestTokenizer(buf); | ||
704 | if (1) { KeyTrans kt; kt.scanTable(buf); } | ||
705 | } | ||
706 | */ | ||
diff --git a/core/apps/embeddedkonsole/keytrans.h b/core/apps/embeddedkonsole/keytrans.h new file mode 100644 index 0000000..ef6ed15 --- a/dev/null +++ b/core/apps/embeddedkonsole/keytrans.h | |||
@@ -0,0 +1,93 @@ | |||
1 | /* -------------------------------------------------------------------------- */ | ||
2 | /* */ | ||
3 | /* [keytrans.h] X Terminal Emulation */ | ||
4 | /* */ | ||
5 | /* -------------------------------------------------------------------------- */ | ||
6 | /* */ | ||
7 | /* Copyright (c) 1997,1998 by Lars Doelle <lars.doelle@on-line.de> */ | ||
8 | /* */ | ||
9 | /* This file is part of Konsole - an X terminal for KDE */ | ||
10 | /* */ | ||
11 | /* -------------------------------------------------------------------------- */ | ||
12 | /* */ | ||
13 | /* Ported Konsole to Qt/Embedded */ | ||
14 | /* */ | ||
15 | /* Copyright (C) 2000 by John Ryland <jryland@trolltech.com> */ | ||
16 | /* */ | ||
17 | /* -------------------------------------------------------------------------- */ | ||
18 | |||
19 | #ifndef KEYTRANS_H | ||
20 | #define KEYTRANS_H | ||
21 | |||
22 | #include <qstring.h> | ||
23 | #include <qlist.h> | ||
24 | #include <qiodevice.h> | ||
25 | |||
26 | #define BITS_NewLine 0 | ||
27 | #define BITS_BsHack 1 | ||
28 | #define BITS_Ansi 2 | ||
29 | #define BITS_AppCuKeys 3 | ||
30 | #define BITS_Control 4 | ||
31 | #define BITS_Shift 5 | ||
32 | #define BITS_Alt 6 | ||
33 | #define BITS_COUNT 7 | ||
34 | |||
35 | #define CMD_send 0 | ||
36 | #define CMD_emitSelection 1 | ||
37 | #define CMD_scrollPageUp 2 | ||
38 | #define CMD_scrollPageDown 3 | ||
39 | #define CMD_scrollLineUp 4 | ||
40 | #define CMD_scrollLineDown 5 | ||
41 | #define CMD_prevSession 6 | ||
42 | #define CMD_nextSession 7 | ||
43 | |||
44 | #define BITS(x,v) ((((v)!=0)<<(x))) | ||
45 | |||
46 | |||
47 | class KeyTrans | ||
48 | { | ||
49 | public: | ||
50 | KeyTrans(); | ||
51 | ~KeyTrans(); | ||
52 | static KeyTrans* defaultKeyTrans(); | ||
53 | static KeyTrans* fromFile(const char* path); | ||
54 | static KeyTrans* find(int numb); | ||
55 | static KeyTrans* find(const char* path); | ||
56 | public: | ||
57 | static int count(); | ||
58 | static void loadAll(); | ||
59 | public: | ||
60 | bool findEntry(int key, int bits, int* cmd, const char** txt, int* len); | ||
61 | private: | ||
62 | void addKeyTrans(); | ||
63 | static KeyTrans* fromDevice(QString path, QIODevice &buf); | ||
64 | public: | ||
65 | class KeyEntry | ||
66 | { | ||
67 | public: | ||
68 | KeyEntry(int ref, int key, int bits, int mask, int cmd, QString txt); | ||
69 | ~KeyEntry(); | ||
70 | public: | ||
71 | bool matches(int key, int bits, int mask); | ||
72 | QString text(); | ||
73 | public: | ||
74 | int ref; | ||
75 | private: | ||
76 | int key; | ||
77 | int bits; | ||
78 | int mask; | ||
79 | public: | ||
80 | int cmd; | ||
81 | QString txt; | ||
82 | }; | ||
83 | public: | ||
84 | KeyEntry* addEntry(int ref, int key, int bits, int mask, int cmd, QString txt); | ||
85 | private: | ||
86 | QList<KeyEntry> table; | ||
87 | public: //FIXME: we'd do better | ||
88 | QString hdr; | ||
89 | int numb; | ||
90 | QString path; | ||
91 | }; | ||
92 | |||
93 | #endif | ||
diff --git a/core/apps/embeddedkonsole/konsole.cpp b/core/apps/embeddedkonsole/konsole.cpp new file mode 100644 index 0000000..7253baf --- a/dev/null +++ b/core/apps/embeddedkonsole/konsole.cpp | |||
@@ -0,0 +1,512 @@ | |||
1 | /* ---------------------------------------------------------------------- */ | ||
2 | /* */ | ||
3 | /* [main.C] Konsole */ | ||
4 | /* */ | ||
5 | /* ---------------------------------------------------------------------- */ | ||
6 | /* */ | ||
7 | /* Copyright (c) 1997,1998 by Lars Doelle <lars.doelle@on-line.de> */ | ||
8 | /* */ | ||
9 | /* This file is part of Konsole, an X terminal. */ | ||
10 | /* */ | ||
11 | /* The material contained in here more or less directly orginates from */ | ||
12 | /* kvt, which is copyright (c) 1996 by Matthias Ettrich <ettrich@kde.org> */ | ||
13 | /* */ | ||
14 | /* ---------------------------------------------------------------------- */ | ||
15 | /* */ | ||
16 | /* Ported Konsole to Qt/Embedded */ | ||
17 | /* */ | ||
18 | /* Copyright (C) 2000 by John Ryland <jryland@trolltech.com> */ | ||
19 | /* */ | ||
20 | /* -------------------------------------------------------------------------- */ | ||
21 | |||
22 | #include <qpe/resource.h> | ||
23 | |||
24 | #include <qdir.h> | ||
25 | #include <qevent.h> | ||
26 | #include <qdragobject.h> | ||
27 | #include <qobjectlist.h> | ||
28 | #include <qtoolbutton.h> | ||
29 | #include <qpe/qpetoolbar.h> | ||
30 | #include <qpushbutton.h> | ||
31 | #include <qfontdialog.h> | ||
32 | #include <qglobal.h> | ||
33 | #include <qpainter.h> | ||
34 | #include <qpe/qpemenubar.h> | ||
35 | #include <qmessagebox.h> | ||
36 | #include <qaction.h> | ||
37 | #include <qapplication.h> | ||
38 | #include <qfontmetrics.h> | ||
39 | #include <qcombobox.h> | ||
40 | #include <qevent.h> | ||
41 | #include <qtabwidget.h> | ||
42 | #include <qtabbar.h> | ||
43 | #include <qpe/config.h> | ||
44 | |||
45 | #include <sys/wait.h> | ||
46 | #include <stdio.h> | ||
47 | #include <stdlib.h> | ||
48 | #include <assert.h> | ||
49 | |||
50 | #include "konsole.h" | ||
51 | #include "keytrans.h" | ||
52 | |||
53 | class EKNumTabBar : public QTabBar { | ||
54 | public: | ||
55 | void numberTabs() | ||
56 | { | ||
57 | // Yes, it really is this messy. QTabWidget needs functions | ||
58 | // that provide acces to tabs in a sequential way. | ||
59 | int m=INT_MIN; | ||
60 | for (int i=0; i<count(); i++) { | ||
61 | QTab* left=0; | ||
62 | QListIterator<QTab> it(*tabList()); | ||
63 | int x=INT_MAX; | ||
64 | for( QTab* t; (t=it.current()); ++it ) { | ||
65 | int tx = t->rect().x(); | ||
66 | if ( tx<x && tx>m ) { | ||
67 | x = tx; | ||
68 | left = t; | ||
69 | } | ||
70 | } | ||
71 | if ( left ) { | ||
72 | left->setText(QString::number(i+1)); | ||
73 | m = left->rect().x(); | ||
74 | } | ||
75 | } | ||
76 | } | ||
77 | }; | ||
78 | |||
79 | class EKNumTabWidget : public QTabWidget { | ||
80 | public: | ||
81 | EKNumTabWidget(QWidget* parent) : QTabWidget(parent) | ||
82 | { | ||
83 | } | ||
84 | |||
85 | void addTab(QWidget* w) | ||
86 | { | ||
87 | QTab* t = new QTab(QString::number(tabBar()->count()+1)); | ||
88 | QTabWidget::addTab(w,t); | ||
89 | } | ||
90 | |||
91 | void removeTab(QWidget* w) | ||
92 | { | ||
93 | removePage(w); | ||
94 | ((EKNumTabBar*)tabBar())->numberTabs(); | ||
95 | } | ||
96 | }; | ||
97 | |||
98 | // This could be configurable or dynamicly generated from the bash history | ||
99 | // file of the user | ||
100 | static const char *commonCmds[] = | ||
101 | { | ||
102 | "ls ", | ||
103 | //"ls -la ", | ||
104 | "cd ", | ||
105 | "pwd", | ||
106 | //"cat", | ||
107 | //"less ", | ||
108 | //"vi ", | ||
109 | //"man ", | ||
110 | "echo ", | ||
111 | "set ", | ||
112 | //"ps", | ||
113 | "ps aux", | ||
114 | //"tar", | ||
115 | //"tar -zxf", | ||
116 | "grep ", | ||
117 | //"grep -i", | ||
118 | //"mkdir", | ||
119 | "cp ", | ||
120 | "mv ", | ||
121 | "rm ", | ||
122 | "rmdir ", | ||
123 | //"chmod", | ||
124 | //"su", | ||
125 | // "top", | ||
126 | //"find", | ||
127 | //"make", | ||
128 | //"tail", | ||
129 | "cardctl eject", | ||
130 | "ifconfig ", | ||
131 | // "iwconfig eth0 ", | ||
132 | "nc localhost 7777", | ||
133 | "nc localhost 7776", | ||
134 | //"mount /dev/hda1", | ||
135 | |||
136 | /* | ||
137 | "gzip", | ||
138 | "gunzip", | ||
139 | "chgrp", | ||
140 | "chown", | ||
141 | "date", | ||
142 | "dd", | ||
143 | "df", | ||
144 | "dmesg", | ||
145 | "fuser", | ||
146 | "hostname", | ||
147 | "kill", | ||
148 | "killall", | ||
149 | "ln", | ||
150 | "ping", | ||
151 | "mount", | ||
152 | "more", | ||
153 | "sort", | ||
154 | "touch", | ||
155 | "umount", | ||
156 | "mknod", | ||
157 | "netstat", | ||
158 | */ | ||
159 | |||
160 | "exit", | ||
161 | NULL | ||
162 | }; | ||
163 | |||
164 | |||
165 | Konsole::Konsole(QWidget* parent, const char* name, WFlags fl) : | ||
166 | QMainWindow(parent, name, fl) | ||
167 | { | ||
168 | QStrList args; | ||
169 | init("/bin/sh",args); | ||
170 | } | ||
171 | |||
172 | Konsole::Konsole(const char* name, const char* _pgm, QStrList & _args, int) | ||
173 | : QMainWindow(0, name) | ||
174 | { | ||
175 | init(_pgm,_args); | ||
176 | } | ||
177 | |||
178 | void Konsole::init(const char* _pgm, QStrList & _args) | ||
179 | { | ||
180 | b_scroll = TRUE; // histon; | ||
181 | n_keytab = 0; | ||
182 | n_render = 0; | ||
183 | |||
184 | setCaption( tr("Terminal") ); | ||
185 | setIcon( Resource::loadPixmap( "konsole" ) ); | ||
186 | |||
187 | Config cfg("Konsole"); | ||
188 | cfg.setGroup("Konsole"); | ||
189 | |||
190 | // initialize the list of allowed fonts /////////////////////////////////// | ||
191 | cfont = cfg.readNumEntry("FontID", 1); | ||
192 | QFont f = QFont("Micro", 4, QFont::Normal); | ||
193 | f.setFixedPitch(TRUE); | ||
194 | fonts.append(new VTFont(tr("Micro"), f)); | ||
195 | |||
196 | f = QFont("Fixed", 7, QFont::Normal); | ||
197 | f.setFixedPitch(TRUE); | ||
198 | fonts.append(new VTFont(tr("Small Fixed"), f)); | ||
199 | |||
200 | f = QFont("Fixed", 12, QFont::Normal); | ||
201 | f.setFixedPitch(TRUE); | ||
202 | fonts.append(new VTFont(tr("Medium Fixed"), f)); | ||
203 | |||
204 | // create terminal emulation framework //////////////////////////////////// | ||
205 | nsessions = 0; | ||
206 | tab = new EKNumTabWidget(this); | ||
207 | tab->setTabPosition(QTabWidget::Bottom); | ||
208 | connect(tab, SIGNAL(currentChanged(QWidget*)), this, SLOT(switchSession(QWidget*))); | ||
209 | |||
210 | // create terminal toolbar //////////////////////////////////////////////// | ||
211 | setToolBarsMovable( FALSE ); | ||
212 | QPEToolBar *menuToolBar = new QPEToolBar( this ); | ||
213 | menuToolBar->setHorizontalStretchable( TRUE ); | ||
214 | |||
215 | QPEMenuBar *menuBar = new QPEMenuBar( menuToolBar ); | ||
216 | |||
217 | fontList = new QPopupMenu( this ); | ||
218 | for(uint i = 0; i < fonts.count(); i++) { | ||
219 | VTFont *fnt = fonts.at(i); | ||
220 | fontList->insertItem(fnt->getName(), i); | ||
221 | } | ||
222 | fontChanged(cfont); | ||
223 | |||
224 | connect( fontList, SIGNAL( activated(int) ), this, SLOT( fontChanged(int) )); | ||
225 | |||
226 | menuBar->insertItem( tr("Font"), fontList ); | ||
227 | |||
228 | QPEToolBar *toolbar = new QPEToolBar( this ); | ||
229 | |||
230 | QAction *a; | ||
231 | |||
232 | // Button Commands | ||
233 | a = new QAction( tr("New"), Resource::loadPixmap( "konsole" ), QString::null, 0, this, 0 ); | ||
234 | connect( a, SIGNAL( activated() ), this, SLOT( newSession() ) ); a->addTo( toolbar ); | ||
235 | a = new QAction( tr("Enter"), Resource::loadPixmap( "konsole/enter" ), QString::null, 0, this, 0 ); | ||
236 | connect( a, SIGNAL( activated() ), this, SLOT( hitEnter() ) ); a->addTo( toolbar ); | ||
237 | a = new QAction( tr("Space"), Resource::loadPixmap( "konsole/space" ), QString::null, 0, this, 0 ); | ||
238 | connect( a, SIGNAL( activated() ), this, SLOT( hitSpace() ) ); a->addTo( toolbar ); | ||
239 | a = new QAction( tr("Tab"), Resource::loadPixmap( "konsole/tab" ), QString::null, 0, this, 0 ); | ||
240 | connect( a, SIGNAL( activated() ), this, SLOT( hitTab() ) ); a->addTo( toolbar ); | ||
241 | a = new QAction( tr("Up"), Resource::loadPixmap( "konsole/up" ), QString::null, 0, this, 0 ); | ||
242 | connect( a, SIGNAL( activated() ), this, SLOT( hitUp() ) ); a->addTo( toolbar ); | ||
243 | a = new QAction( tr("Down"), Resource::loadPixmap( "konsole/down" ), QString::null, 0, this, 0 ); | ||
244 | connect( a, SIGNAL( activated() ), this, SLOT( hitDown() ) ); a->addTo( toolbar ); | ||
245 | a = new QAction( tr("Paste"), Resource::loadPixmap( "paste" ), QString::null, 0, this, 0 ); | ||
246 | connect( a, SIGNAL( activated() ), this, SLOT( hitPaste() ) ); a->addTo( toolbar ); | ||
247 | /* | ||
248 | a = new QAction( tr("Up"), Resource::loadPixmap( "up" ), QString::null, 0, this, 0 ); | ||
249 | connect( a, SIGNAL( activated() ), this, SLOT( hitUp() ) ); a->addTo( toolbar ); | ||
250 | a = new QAction( tr("Down"), Resource::loadPixmap( "down" ), QString::null, 0, this, 0 ); | ||
251 | connect( a, SIGNAL( activated() ), this, SLOT( hitDown() ) ); a->addTo( toolbar ); | ||
252 | */ | ||
253 | |||
254 | QPEToolBar *secondToolBar = new QPEToolBar( this ); | ||
255 | secondToolBar->setHorizontalStretchable( TRUE ); | ||
256 | |||
257 | QComboBox *commonCombo = new QComboBox( secondToolBar ); | ||
258 | // commonCombo->setEditable( TRUE ); | ||
259 | for (int i = 0; commonCmds[i] != NULL; i++) | ||
260 | commonCombo->insertItem( commonCmds[i], i ); | ||
261 | connect( commonCombo, SIGNAL( activated(int) ), this, SLOT( enterCommand(int) )); | ||
262 | |||
263 | // create applications ///////////////////////////////////////////////////// | ||
264 | setCentralWidget(tab); | ||
265 | |||
266 | // load keymaps //////////////////////////////////////////////////////////// | ||
267 | KeyTrans::loadAll(); | ||
268 | for (int i = 0; i < KeyTrans::count(); i++) | ||
269 | { KeyTrans* s = KeyTrans::find(i); | ||
270 | assert( s ); | ||
271 | } | ||
272 | |||
273 | se_pgm = _pgm; | ||
274 | se_args = _args; | ||
275 | |||
276 | // read and apply default values /////////////////////////////////////////// | ||
277 | resize(321, 321); // Dummy. | ||
278 | QSize currentSize = size(); | ||
279 | if (currentSize != size()) | ||
280 | defaultSize = size(); | ||
281 | } | ||
282 | |||
283 | void Konsole::show() | ||
284 | { | ||
285 | if ( !nsessions ) { | ||
286 | newSession(); | ||
287 | } | ||
288 | QMainWindow::show(); | ||
289 | } | ||
290 | |||
291 | void Konsole::initSession(const char*, QStrList &) | ||
292 | { | ||
293 | QMainWindow::show(); | ||
294 | } | ||
295 | |||
296 | Konsole::~Konsole() | ||
297 | { | ||
298 | while (nsessions > 0) { | ||
299 | doneSession(getTe()->currentSession, 0); | ||
300 | } | ||
301 | |||
302 | Config cfg("Konsole"); | ||
303 | cfg.setGroup("Konsole"); | ||
304 | cfg.writeEntry("FontID", cfont); | ||
305 | } | ||
306 | |||
307 | void Konsole::fontChanged(int f) | ||
308 | { | ||
309 | VTFont* font = fonts.at(f); | ||
310 | if (font != 0) { | ||
311 | for(uint i = 0; i < fonts.count(); i++) { | ||
312 | fontList->setItemChecked(i, (i == (uint) f) ? TRUE : FALSE); | ||
313 | } | ||
314 | |||
315 | cfont = f; | ||
316 | |||
317 | TEWidget* te = getTe(); | ||
318 | if (te != 0) { | ||
319 | te->setVTFont(font->getFont()); | ||
320 | } | ||
321 | } | ||
322 | } | ||
323 | |||
324 | void Konsole::enterCommand(int c) | ||
325 | { | ||
326 | TEWidget* te = getTe(); | ||
327 | if (te != 0) { | ||
328 | QString text = commonCmds[c]; | ||
329 | te->emitText(text); | ||
330 | } | ||
331 | } | ||
332 | |||
333 | void Konsole::hitEnter() | ||
334 | { | ||
335 | TEWidget* te = getTe(); | ||
336 | if (te != 0) { | ||
337 | te->emitText(QString("\r")); | ||
338 | } | ||
339 | } | ||
340 | |||
341 | void Konsole::hitSpace() | ||
342 | { | ||
343 | TEWidget* te = getTe(); | ||
344 | if (te != 0) { | ||
345 | te->emitText(QString(" ")); | ||
346 | } | ||
347 | } | ||
348 | |||
349 | void Konsole::hitTab() | ||
350 | { | ||
351 | TEWidget* te = getTe(); | ||
352 | if (te != 0) { | ||
353 | te->emitText(QString("\t")); | ||
354 | } | ||
355 | } | ||
356 | |||
357 | void Konsole::hitPaste() | ||
358 | { | ||
359 | TEWidget* te = getTe(); | ||
360 | if (te != 0) { | ||
361 | te->pasteClipboard(); | ||
362 | } | ||
363 | } | ||
364 | |||
365 | void Konsole::hitUp() | ||
366 | { | ||
367 | TEWidget* te = getTe(); | ||
368 | if (te != 0) { | ||
369 | QKeyEvent ke( QKeyEvent::KeyPress, Qt::Key_Up, 0, 0); | ||
370 | QApplication::sendEvent( te, &ke ); | ||
371 | } | ||
372 | } | ||
373 | |||
374 | void Konsole::hitDown() | ||
375 | { | ||
376 | TEWidget* te = getTe(); | ||
377 | if (te != 0) { | ||
378 | QKeyEvent ke( QKeyEvent::KeyPress, Qt::Key_Down, 0, 0); | ||
379 | QApplication::sendEvent( te, &ke ); | ||
380 | } | ||
381 | } | ||
382 | |||
383 | /** | ||
384 | This function calculates the size of the external widget | ||
385 | needed for the internal widget to be | ||
386 | */ | ||
387 | QSize Konsole::calcSize(int columns, int lines) { | ||
388 | TEWidget* te = getTe(); | ||
389 | if (te != 0) { | ||
390 | QSize size = te->calcSize(columns, lines); | ||
391 | return size; | ||
392 | } else { | ||
393 | QSize size; | ||
394 | return size; | ||
395 | } | ||
396 | } | ||
397 | |||
398 | /** | ||
399 | sets application window to a size based on columns X lines of the te | ||
400 | guest widget. Call with (0,0) for setting default size. | ||
401 | */ | ||
402 | |||
403 | void Konsole::setColLin(int columns, int lines) | ||
404 | { | ||
405 | if ((columns==0) || (lines==0)) | ||
406 | { | ||
407 | if (defaultSize.isEmpty()) // not in config file : set default value | ||
408 | { | ||
409 | defaultSize = calcSize(80,24); | ||
410 | // notifySize(24,80); // set menu items (strange arg order !) | ||
411 | } | ||
412 | resize(defaultSize); | ||
413 | } else { | ||
414 | resize(calcSize(columns, lines)); | ||
415 | // notifySize(lines,columns); // set menu items (strange arg order !) | ||
416 | } | ||
417 | } | ||
418 | |||
419 | /* | ||
420 | void Konsole::setFont(int fontno) | ||
421 | { | ||
422 | QFont f; | ||
423 | if (fontno == 0) | ||
424 | f = defaultFont = QFont( "Helvetica", 12 ); | ||
425 | else | ||
426 | if (fonts[fontno][0] == '-') | ||
427 | f.setRawName( fonts[fontno] ); | ||
428 | else | ||
429 | { | ||
430 | f.setFamily(fonts[fontno]); | ||
431 | f.setRawMode( TRUE ); | ||
432 | } | ||
433 | if ( !f.exactMatch() && fontno != 0) | ||
434 | { | ||
435 | QString msg = i18n("Font `%1' not found.\nCheck README.linux.console for help.").arg(fonts[fontno]); | ||
436 | QMessageBox(this, msg); | ||
437 | return; | ||
438 | } | ||
439 | if (se) se->setFontNo(fontno); | ||
440 | te->setVTFont(f); | ||
441 | n_font = fontno; | ||
442 | } | ||
443 | */ | ||
444 | |||
445 | // --| color selection |------------------------------------------------------- | ||
446 | |||
447 | void Konsole::changeColumns(int columns) | ||
448 | { | ||
449 | TEWidget* te = getTe(); | ||
450 | if (te != 0) { | ||
451 | setColLin(columns,te->Lines()); | ||
452 | te->update(); | ||
453 | } | ||
454 | } | ||
455 | |||
456 | //FIXME: If a child dies during session swap, | ||
457 | // this routine might be called before | ||
458 | // session swap is completed. | ||
459 | |||
460 | void Konsole::doneSession(TESession*, int ) | ||
461 | { | ||
462 | TEWidget *te = getTe(); | ||
463 | if (te != 0) { | ||
464 | te->currentSession->setConnect(FALSE); | ||
465 | tab->removeTab(te); | ||
466 | delete te->currentSession; | ||
467 | delete te; | ||
468 | nsessions--; | ||
469 | } | ||
470 | |||
471 | if (nsessions == 0) { | ||
472 | close(); | ||
473 | } | ||
474 | } | ||
475 | |||
476 | |||
477 | void Konsole::newSession() { | ||
478 | TEWidget* te = new TEWidget(tab); | ||
479 | te->setBackgroundMode(PaletteBase); | ||
480 | te->setVTFont(fonts.at(cfont)->getFont()); | ||
481 | tab->addTab(te); | ||
482 | TESession* se = new TESession(this, te, se_pgm, se_args, "xterm"); | ||
483 | te->currentSession = se; | ||
484 | connect( se, SIGNAL(done(TESession*,int)), this, SLOT(doneSession(TESession*,int)) ); | ||
485 | se->run(); | ||
486 | se->setConnect(TRUE); | ||
487 | se->setHistory(b_scroll); | ||
488 | tab->setCurrentPage(nsessions); | ||
489 | nsessions++; | ||
490 | } | ||
491 | |||
492 | TEWidget* Konsole::getTe() { | ||
493 | if (nsessions) { | ||
494 | return (TEWidget *) tab->currentPage(); | ||
495 | } else { | ||
496 | return 0; | ||
497 | } | ||
498 | } | ||
499 | |||
500 | void Konsole::switchSession(QWidget* w) { | ||
501 | TEWidget* te = (TEWidget *) w; | ||
502 | |||
503 | QFont teFnt = te->getVTFont(); | ||
504 | for(uint i = 0; i < fonts.count(); i++) { | ||
505 | VTFont *fnt = fonts.at(i); | ||
506 | bool cf = fnt->getFont() == teFnt; | ||
507 | fontList->setItemChecked(i, cf); | ||
508 | if (cf) { | ||
509 | cfont = i; | ||
510 | } | ||
511 | } | ||
512 | } | ||
diff --git a/core/apps/embeddedkonsole/konsole.h b/core/apps/embeddedkonsole/konsole.h new file mode 100644 index 0000000..819ea5d --- a/dev/null +++ b/core/apps/embeddedkonsole/konsole.h | |||
@@ -0,0 +1,125 @@ | |||
1 | /* ----------------------------------------------------------------------- */ | ||
2 | /* */ | ||
3 | /* [konsole.h] Konsole */ | ||
4 | /* */ | ||
5 | /* -------------------------------------------------------------------------- */ | ||
6 | /* */ | ||
7 | /* Copyright (c) 1997,1998 by Lars Doelle <lars.doelle@on-line.de> */ | ||
8 | /* */ | ||
9 | /* This file is part of Konsole, an X terminal. */ | ||
10 | /* */ | ||
11 | /* The material contained in here more or less directly orginates from */ | ||
12 | /* kvt, which is copyright (c) 1996 by Matthias Ettrich <ettrich@kde.org> */ | ||
13 | /* */ | ||
14 | /* -------------------------------------------------------------------------- */ | ||
15 | /* */ | ||
16 | /* Ported Konsole to Qt/Embedded */ | ||
17 | /* */ | ||
18 | /* Copyright (C) 2000 by John Ryland <jryland@trolltech.com> */ | ||
19 | /* */ | ||
20 | /* -------------------------------------------------------------------------- */ | ||
21 | |||
22 | #ifndef KONSOLE_H | ||
23 | #define KONSOLE_H | ||
24 | |||
25 | |||
26 | #include <qmainwindow.h> | ||
27 | #include <qaction.h> | ||
28 | #include <qpopupmenu.h> | ||
29 | #include <qstrlist.h> | ||
30 | #include <qintdict.h> | ||
31 | #include <qptrdict.h> | ||
32 | #include <qtabwidget.h> | ||
33 | |||
34 | #include "MyPty.h" | ||
35 | #include "TEWidget.h" | ||
36 | #include "TEmuVt102.h" | ||
37 | #include "session.h" | ||
38 | |||
39 | class EKNumTabWidget; | ||
40 | |||
41 | class Konsole : public QMainWindow | ||
42 | { | ||
43 | Q_OBJECT | ||
44 | |||
45 | public: | ||
46 | |||
47 | Konsole(QWidget* parent = 0, const char* name = 0, WFlags fl = 0); | ||
48 | Konsole(const char * name, const char* pgm, QStrList & _args, int histon); | ||
49 | ~Konsole(); | ||
50 | void setColLin(int columns, int lines); | ||
51 | |||
52 | void show(); | ||
53 | |||
54 | private slots: | ||
55 | void doneSession(TESession*,int); | ||
56 | void changeColumns(int); | ||
57 | void fontChanged(int); | ||
58 | void enterCommand(int); | ||
59 | void hitEnter(); | ||
60 | void hitSpace(); | ||
61 | void hitTab(); | ||
62 | void hitPaste(); | ||
63 | void hitUp(); | ||
64 | void hitDown(); | ||
65 | void switchSession(QWidget *); | ||
66 | void newSession(); | ||
67 | |||
68 | private: | ||
69 | void init(const char* _pgm, QStrList & _args); | ||
70 | void initSession(const char* _pgm, QStrList & _args); | ||
71 | void runSession(TESession* s); | ||
72 | void setColorPixmaps(); | ||
73 | void setHistory(bool); | ||
74 | QSize calcSize(int columns, int lines); | ||
75 | TEWidget* getTe(); | ||
76 | |||
77 | private: | ||
78 | class VTFont | ||
79 | { | ||
80 | public: | ||
81 | VTFont(QString name, QFont& font) | ||
82 | { | ||
83 | this->name = name; | ||
84 | this->font = font; | ||
85 | } | ||
86 | |||
87 | QFont& getFont() | ||
88 | { | ||
89 | return font; | ||
90 | } | ||
91 | |||
92 | QString getName() | ||
93 | { | ||
94 | return name; | ||
95 | } | ||
96 | |||
97 | private: | ||
98 | QString name; | ||
99 | QFont font; | ||
100 | }; | ||
101 | |||
102 | EKNumTabWidget* tab; | ||
103 | int nsessions; | ||
104 | QList<VTFont> fonts; | ||
105 | int cfont; | ||
106 | QCString se_pgm; | ||
107 | QStrList se_args; | ||
108 | |||
109 | QPopupMenu* fontList; | ||
110 | |||
111 | // history scrolling I think | ||
112 | bool b_scroll; | ||
113 | |||
114 | int n_keytab; | ||
115 | int n_scroll; | ||
116 | int n_render; | ||
117 | QString pmPath; // pixmap path | ||
118 | QString dropText; | ||
119 | QFont defaultFont; | ||
120 | QSize defaultSize; | ||
121 | |||
122 | }; | ||
123 | |||
124 | #endif | ||
125 | |||
diff --git a/core/apps/embeddedkonsole/main.cpp b/core/apps/embeddedkonsole/main.cpp new file mode 100644 index 0000000..e3ba346 --- a/dev/null +++ b/core/apps/embeddedkonsole/main.cpp | |||
@@ -0,0 +1,60 @@ | |||
1 | /* ---------------------------------------------------------------------- */ | ||
2 | /* */ | ||
3 | /* [main.C] Konsole */ | ||
4 | /* */ | ||
5 | /* ---------------------------------------------------------------------- */ | ||
6 | /* */ | ||
7 | /* Copyright (c) 1997,1998 by Lars Doelle <lars.doelle@on-line.de> */ | ||
8 | /* */ | ||
9 | /* This file is part of Konsole, an X terminal. */ | ||
10 | /* */ | ||
11 | /* The material contained in here more or less directly orginates from */ | ||
12 | /* kvt, which is copyright (c) 1996 by Matthias Ettrich <ettrich@kde.org> */ | ||
13 | /* */ | ||
14 | /* ---------------------------------------------------------------------- */ | ||
15 | /* */ | ||
16 | /* Ported Konsole to Qt/Embedded */ | ||
17 | /* */ | ||
18 | /* Copyright (C) 2000 by John Ryland <jryland@trolltech.com> */ | ||
19 | /* */ | ||
20 | /* -------------------------------------------------------------------------- */ | ||
21 | |||
22 | #include "konsole.h" | ||
23 | |||
24 | #include <qpe/qpeapplication.h> | ||
25 | |||
26 | #include <qfile.h> | ||
27 | |||
28 | #include <unistd.h> | ||
29 | #include <stdio.h> | ||
30 | #include <stdlib.h> | ||
31 | |||
32 | |||
33 | /* --| main |------------------------------------------------------ */ | ||
34 | int main(int argc, char* argv[]) | ||
35 | { | ||
36 | setuid(getuid()); setgid(getgid()); // drop privileges | ||
37 | |||
38 | QPEApplication a( argc, argv ); | ||
39 | |||
40 | #ifdef FAKE_CTRL_AND_ALT | ||
41 | QPEApplication::grabKeyboard(); // for CTRL and ALT | ||
42 | #endif | ||
43 | |||
44 | QStrList tmp; | ||
45 | const char* shell = getenv("SHELL"); | ||
46 | if (shell == NULL || *shell == '\0') | ||
47 | shell = "/bin/sh"; | ||
48 | |||
49 | // sh is completely broken on familiar. Let's try to get something better | ||
50 | if ( qstrcmp( shell, "/bin/shell" ) == 0 && QFile::exists( "/bin/bash" ) ) | ||
51 | shell = "/bin/bash"; | ||
52 | |||
53 | putenv((char*)"COLORTERM="); // to trigger mc's color detection | ||
54 | |||
55 | Konsole m( "test", shell, tmp, TRUE ); | ||
56 | m.setCaption( Konsole::tr("Terminal") ); | ||
57 | a.showMainWidget( &m ); | ||
58 | |||
59 | return a.exec(); | ||
60 | } | ||
diff --git a/core/apps/embeddedkonsole/qpe-embeddedkonsole.control b/core/apps/embeddedkonsole/qpe-embeddedkonsole.control new file mode 100644 index 0000000..9b7c355 --- a/dev/null +++ b/core/apps/embeddedkonsole/qpe-embeddedkonsole.control | |||
@@ -0,0 +1,9 @@ | |||
1 | Files: bin/embeddedkonsole apps/Applications/embeddedkonsole.desktop pics/konsole etc/keytabs/* | ||
2 | Priority: optional | ||
3 | Section: qpe/applications | ||
4 | Maintainer: Warwick Allison <warwick@trolltech.com> | ||
5 | Architecture: arm | ||
6 | Version: $QPE_VERSION-4 | ||
7 | Depends: qpe-base ($QPE_VERSION), ptydevs | ||
8 | Description: KDE's konsole (shell terminal) | ||
9 | Ported to the Qtopia environment. | ||
diff --git a/core/apps/embeddedkonsole/session.cpp b/core/apps/embeddedkonsole/session.cpp new file mode 100644 index 0000000..520af86 --- a/dev/null +++ b/core/apps/embeddedkonsole/session.cpp | |||
@@ -0,0 +1,157 @@ | |||
1 | /* -------------------------------------------------------------------------- */ | ||
2 | /* */ | ||
3 | /* Ported Konsole to Qt/Embedded */ | ||
4 | /* */ | ||
5 | /* Copyright (C) 2000 by John Ryland <jryland@trolltech.com> */ | ||
6 | /* */ | ||
7 | /* -------------------------------------------------------------------------- */ | ||
8 | #include "session.h" | ||
9 | #include <qpushbutton.h> | ||
10 | // #include <kdebug.h> | ||
11 | |||
12 | #include <stdlib.h> | ||
13 | |||
14 | #define HERE fprintf(stderr,"%s(%d): here\n",__FILE__,__LINE__) | ||
15 | |||
16 | /*! \class TESession | ||
17 | |||
18 | Sessions are combinations of TEPTy and Emulations. | ||
19 | |||
20 | The stuff in here does not belong to the terminal emulation framework, | ||
21 | but to main.C. It serves it's duty by providing a single reference | ||
22 | to TEPTy/Emulation pairs. In fact, it is only there to demonstrate one | ||
23 | of the abilities of the framework - multible sessions. | ||
24 | */ | ||
25 | |||
26 | TESession::TESession(QMainWindow* main, TEWidget* te, const char* _pgm, QStrList & _args, const char *_term) : schema_no(0), font_no(3), pgm(_pgm), args(_args) | ||
27 | { | ||
28 | // sh = new TEPty(); | ||
29 | sh = new MyPty(); | ||
30 | em = new TEmuVt102(te); | ||
31 | |||
32 | term = _term; | ||
33 | |||
34 | sh->setSize(te->Lines(),te->Columns()); // not absolutely nessesary | ||
35 | QObject::connect( sh,SIGNAL(block_in(const char*,int)), | ||
36 | em,SLOT(onRcvBlock(const char*,int)) ); | ||
37 | QObject::connect( em,SIGNAL(ImageSizeChanged(int,int)), | ||
38 | sh,SLOT(setSize(int,int))); | ||
39 | |||
40 | // 'main' should do those connects itself, somehow. | ||
41 | // These aren't KTMW's slots, but konsole's.(David) | ||
42 | |||
43 | /* | ||
44 | QObject::connect( em,SIGNAL(ImageSizeChanged(int,int)), | ||
45 | main,SLOT(notifySize(int,int))); | ||
46 | */ | ||
47 | QObject::connect( em,SIGNAL(sndBlock(const char*,int)), | ||
48 | sh,SLOT(send_bytes(const char*,int)) ); | ||
49 | QObject::connect( em,SIGNAL(changeColumns(int)), | ||
50 | main,SLOT(changeColumns(int)) ); | ||
51 | /* | ||
52 | QObject::connect( em,SIGNAL(changeTitle(int, const QString&)), | ||
53 | main,SLOT(changeTitle(int, const QString&)) ); | ||
54 | */ | ||
55 | QObject::connect( sh,SIGNAL(done(int)), this,SLOT(done(int)) ); | ||
56 | } | ||
57 | |||
58 | |||
59 | |||
60 | void TESession::run() | ||
61 | { | ||
62 | //kdDebug() << "Running the session!" << pgm << "\n"; | ||
63 | sh->run(pgm,args,term.data(),FALSE); | ||
64 | } | ||
65 | |||
66 | void TESession::kill(int ) // signal) | ||
67 | { | ||
68 | // sh->kill(signal); | ||
69 | } | ||
70 | |||
71 | TESession::~TESession() | ||
72 | { | ||
73 | QObject::disconnect( sh, SIGNAL( done( int ) ), | ||
74 | this, SLOT( done( int ) ) ); | ||
75 | delete em; | ||
76 | delete sh; | ||
77 | } | ||
78 | |||
79 | void TESession::setConnect(bool c) | ||
80 | { | ||
81 | em->setConnect(c); | ||
82 | } | ||
83 | |||
84 | void TESession::done(int status) | ||
85 | { | ||
86 | emit done(this,status); | ||
87 | } | ||
88 | |||
89 | void TESession::terminate() | ||
90 | { | ||
91 | delete this; | ||
92 | } | ||
93 | |||
94 | TEmulation* TESession::getEmulation() | ||
95 | { | ||
96 | return em; | ||
97 | } | ||
98 | |||
99 | // following interfaces might be misplaced /// | ||
100 | |||
101 | int TESession::schemaNo() | ||
102 | { | ||
103 | return schema_no; | ||
104 | } | ||
105 | |||
106 | int TESession::keymap() | ||
107 | { | ||
108 | return keymap_no; | ||
109 | } | ||
110 | |||
111 | int TESession::fontNo() | ||
112 | { | ||
113 | return font_no; | ||
114 | } | ||
115 | |||
116 | const char* TESession::emuName() | ||
117 | { | ||
118 | return term.data(); | ||
119 | } | ||
120 | |||
121 | void TESession::setSchemaNo(int sn) | ||
122 | { | ||
123 | schema_no = sn; | ||
124 | } | ||
125 | |||
126 | void TESession::setKeymapNo(int kn) | ||
127 | { | ||
128 | keymap_no = kn; | ||
129 | em->setKeytrans(kn); | ||
130 | } | ||
131 | |||
132 | void TESession::setFontNo(int fn) | ||
133 | { | ||
134 | font_no = fn; | ||
135 | } | ||
136 | |||
137 | void TESession::setTitle(const QString& title) | ||
138 | { | ||
139 | this->title = title; | ||
140 | } | ||
141 | |||
142 | const QString& TESession::Title() | ||
143 | { | ||
144 | return title; | ||
145 | } | ||
146 | |||
147 | void TESession::setHistory(bool on) | ||
148 | { | ||
149 | em->setHistory( on ); | ||
150 | } | ||
151 | |||
152 | bool TESession::history() | ||
153 | { | ||
154 | return em->history(); | ||
155 | } | ||
156 | |||
157 | // #include "session.moc" | ||
diff --git a/core/apps/embeddedkonsole/session.h b/core/apps/embeddedkonsole/session.h new file mode 100644 index 0000000..4a61569 --- a/dev/null +++ b/core/apps/embeddedkonsole/session.h | |||
@@ -0,0 +1,93 @@ | |||
1 | /* -------------------------------------------------------------------------- */ | ||
2 | /* */ | ||
3 | /* [session.h] Testbed for TE framework */ | ||
4 | /* */ | ||
5 | /* -------------------------------------------------------------------------- */ | ||
6 | /* */ | ||
7 | /* Copyright (c) 1997,1998 by Lars Doelle <lars.doelle@on-line.de> */ | ||
8 | /* */ | ||
9 | /* This file is part of Konsole, an X terminal. */ | ||
10 | /* */ | ||
11 | /* -------------------------------------------------------------------------- */ | ||
12 | /* */ | ||
13 | /* Ported Konsole to Qt/Embedded */ | ||
14 | /* */ | ||
15 | /* Copyright (C) 2000 by John Ryland <jryland@trolltech.com> */ | ||
16 | /* */ | ||
17 | /* -------------------------------------------------------------------------- */ | ||
18 | |||
19 | #ifndef SESSION_H | ||
20 | #define SESSION_H | ||
21 | |||
22 | #include <qapplication.h> | ||
23 | #include <qmainwindow.h> | ||
24 | #include <qstrlist.h> | ||
25 | |||
26 | #include "MyPty.h" | ||
27 | #include "TEWidget.h" | ||
28 | #include "TEmuVt102.h" | ||
29 | |||
30 | class TESession : public QObject | ||
31 | { Q_OBJECT | ||
32 | |||
33 | public: | ||
34 | |||
35 | TESession(QMainWindow* main, TEWidget* w, | ||
36 | const char* pgm, QStrList & _args, | ||
37 | const char* term); | ||
38 | ~TESession(); | ||
39 | |||
40 | public: | ||
41 | |||
42 | void setConnect(bool r); | ||
43 | TEmulation* getEmulation(); // to control emulation | ||
44 | bool isSecure(); | ||
45 | |||
46 | public: | ||
47 | |||
48 | int schemaNo(); | ||
49 | int fontNo(); | ||
50 | const char* emuName(); | ||
51 | const QString& Title(); | ||
52 | bool history(); | ||
53 | int keymap(); | ||
54 | |||
55 | void setHistory(bool on); | ||
56 | void setSchemaNo(int sn); | ||
57 | void setKeymapNo(int kn); | ||
58 | void setFontNo(int fn); | ||
59 | void setTitle(const QString& title); | ||
60 | void kill(int signal); | ||
61 | |||
62 | public slots: | ||
63 | |||
64 | void run(); | ||
65 | void done(int status); | ||
66 | void terminate(); | ||
67 | |||
68 | signals: | ||
69 | |||
70 | void done(TESession*, int); | ||
71 | |||
72 | private: | ||
73 | |||
74 | // TEPty* sh; | ||
75 | MyPty* sh; | ||
76 | TEWidget* te; | ||
77 | TEmulation* em; | ||
78 | |||
79 | //FIXME: using the indices here | ||
80 | // is propably very bad. We should | ||
81 | // use a persistent reference instead. | ||
82 | int schema_no; | ||
83 | int font_no; | ||
84 | int keymap_no; | ||
85 | QString title; | ||
86 | |||
87 | const char* pgm; | ||
88 | QStrList args; | ||
89 | |||
90 | QCString term; | ||
91 | }; | ||
92 | |||
93 | #endif | ||