summaryrefslogtreecommitdiff
path: root/noncore/apps/opie-console/emulation_layer.cpp~
Unidiff
Diffstat (limited to 'noncore/apps/opie-console/emulation_layer.cpp~') (more/less context) (ignore whitespace changes)
-rw-r--r--noncore/apps/opie-console/emulation_layer.cpp~373
1 files changed, 373 insertions, 0 deletions
diff --git a/noncore/apps/opie-console/emulation_layer.cpp~ b/noncore/apps/opie-console/emulation_layer.cpp~
new file mode 100644
index 0000000..e65fd4b
--- a/dev/null
+++ b/noncore/apps/opie-console/emulation_layer.cpp~
@@ -0,0 +1,373 @@
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 /* */
20/* Modified to suit opie-console */
21 /* */
22/* Copyright (C) 2002 by opie developers <opie@handhelds.org> */
23 /* */
24/* ------------------------------------------------------------------------- */
25
26/*! \class TEmulation
27
28 \brief Mediator between TEWidget and TEScreen.
29
30 This class is responsible to scan the escapes sequences of the terminal
31 emulation and to map it to their corresponding semantic complements.
32 Thus this module knows mainly about decoding escapes sequences and
33 is a stateless device w.r.t. the semantics.
34
35 It is also responsible to refresh the TEWidget by certain rules.
36
37 \sa TEWidget \sa TEScreen
38
39 \par A note on refreshing
40
41 Although the modifications to the current screen image could immediately
42 be propagated via `TEWidget' to the graphical surface, we have chosen
43 another way here.
44
45 The reason for doing so is twofold.
46
47 First, experiments show that directly displaying the operation results
48 in slowing down the overall performance of emulations. Displaying
49 individual characters using X11 creates a lot of overhead.
50
51 Second, by using the following refreshing method, the screen operations
52 can be completely separated from the displaying. This greatly simplifies
53 the programmer's task of coding and maintaining the screen operations,
54 since one need not worry about differential modifications on the
55 display affecting the operation of concern.
56
57 We use a refreshing algorithm here that has been adoped from rxvt/kvt.
58
59 By this, refreshing is driven by a timer, which is (re)started whenever
60 a new bunch of data to be interpreted by the emulation arives at `onRcvBlock'.
61 As soon as no more data arrive for `BULK_TIMEOUT' milliseconds, we trigger
62 refresh. This rule suits both bulk display operation as done by curses as
63 well as individual characters typed.
64 (BULK_TIMEOUT < 1000 / max characters received from keyboard per second).
65
66 Additionally, we trigger refreshing by newlines comming in to make visual
67 snapshots of lists as produced by `cat', `ls' and likely programs, thereby
68 producing the illusion of a permanent and immediate display operation.
69
70 As a sort of catch-all needed for cases where none of the above
71 conditions catch, the screen refresh is also triggered by a count
72 of incoming bulks (`bulk_incnt').
73*/
74
75/* FIXME
76 - evtl. the bulk operations could be made more transparent.
77*/
78
79#include "emulation_layer.h"
80#include "widget.h"
81#include "TEScreen.h"
82#include <stdio.h>
83#include <stdlib.h>
84#include <unistd.h>
85#include <qkeycode.h>
86
87
88/* ------------------------------------------------------------------------- */
89/* */
90/* EmulationLayer */
91/* */
92/* ------------------------------------------------------------------------- */
93
94#define CNTL(c) ((c)-'@')
95
96/*!
97*/
98
99EmulationLayer::EmulationLayer(TEWidget* gui)
100: decoder((QTextDecoder*)NULL)
101{
102 this->gui = gui;
103
104 screen[0] = new TEScreen(gui->Lines(),gui->Columns());
105 screen[1] = new TEScreen(gui->Lines(),gui->Columns());
106 scr = screen[0];
107
108 bulk_nlcnt = 0; // reset bulk newline counter
109 bulk_incnt = 0; // reset bulk counter
110 connected = FALSE;
111
112 QObject::connect(&bulk_timer, SIGNAL(timeout()), this, SLOT(showBulk()) );
113 QObject::connect(gui,SIGNAL(changedImageSizeSignal(int,int)),
114 this,SLOT(onImageSizeChange(int,int)));
115 QObject::connect(gui,SIGNAL(changedHistoryCursor(int)),
116 this,SLOT(onHistoryCursorChange(int)));
117 QObject::connect(gui,SIGNAL(keyPressedSignal(QKeyEvent*)),
118 this,SLOT(onKeyPress(QKeyEvent*)));
119 QObject::connect(gui,SIGNAL(beginSelectionSignal(const int,const int)),
120 this,SLOT(onSelectionBegin(const int,const int)) );
121 QObject::connect(gui,SIGNAL(extendSelectionSignal(const int,const int)),
122 this,SLOT(onSelectionExtend(const int,const int)) );
123 QObject::connect(gui,SIGNAL(endSelectionSignal(const BOOL)),
124 this,SLOT(setSelection(const BOOL)) );
125 QObject::connect(gui,SIGNAL(clearSelectionSignal()),
126 this,SLOT(clearSelection()) );
127}
128
129/*!
130*/
131
132EmulationLayer::~EmulationLayer()
133{
134 delete screen[0];
135 delete screen[1];
136 bulk_timer.stop();
137}
138
139/*! change between primary and alternate screen
140*/
141
142void EmulationLayer::setScreen(int n)
143{
144 scr = screen[n&1];
145}
146
147void EmulationLayer::setHistory(bool on)
148{
149 screen[0]->setScroll(on);
150 if (!connected) return;
151 showBulk();
152}
153
154bool EmulationLayer::history()
155{
156 return screen[0]->hasScroll();
157}
158
159void EmulationLayer::setCodec(int c)
160{
161 //FIXME: check whether we have to free codec
162 codec = c ? QTextCodec::codecForName("utf8")
163 : QTextCodec::codecForLocale();
164 if (decoder) delete decoder;
165 decoder = codec->makeDecoder();
166}
167
168void EmulationLayer::setKeytrans(int no)
169{
170 keytrans = KeyTrans::find(no);
171}
172
173void EmulationLayer::setKeytrans(const char * no)
174{
175 keytrans = KeyTrans::find(no);
176}
177
178// Interpreting Codes ---------------------------------------------------------
179
180/*
181 This section deals with decoding the incoming character stream.
182 Decoding means here, that the stream is first seperated into `tokens'
183 which are then mapped to a `meaning' provided as operations by the
184 `Screen' class.
185*/
186
187/*!
188*/
189
190void EmulationLayer::onRcvChar(int c)
191// process application unicode input to terminal
192// this is a trivial scanner
193{
194 c &= 0xff;
195 switch (c)
196 {
197 case '\b' : scr->BackSpace(); break;
198 case '\t' : scr->Tabulate(); break;
199 case '\n' : scr->NewLine(); break;
200 case '\r' : scr->Return(); break;
201 case 0x07 : gui->Bell(); break;
202 default : scr->ShowCharacter(c); break;
203 };
204}
205
206/* ------------------------------------------------------------------------- */
207/* */
208/* Keyboard Handling */
209/* */
210/* ------------------------------------------------------------------------- */
211
212/*!
213*/
214
215void EmulationLayer::onKeyPress( QKeyEvent* ev )
216{
217 if (!connected) return; // someone else gets the keys
218 if (scr->getHistCursor() != scr->getHistLines());
219 scr->setHistCursor(scr->getHistLines());
220 if (!ev->text().isEmpty())
221 { // A block of text
222 // Note that the text is proper unicode.
223 // We should do a conversion here, but since this
224 // routine will never be used, we simply emit plain ascii.
225 sendString( ev->text().ascii() ); //,ev->text().length());
226 }
227 else if (ev->ascii()>0)
228 {
229 QByteArray c = QByteArray( 1 );
230 c.at( 0 ) = ev->ascii();
231 // ibot: qbytearray is emited not char*
232 emit sndBlock( (QByteArray) c );
233 }
234}
235
236// Unblocking, Byte to Unicode translation --------------------------------- --
237
238/*
239 We are doing code conversion from locale to unicode first.
240*/
241
242void EmulationLayer::onRcvBlock(const QByteArray &s )
243{
244 bulkStart();
245 bulk_incnt += 1;
246 for (int i = 0; i < s.size(); i++)
247 {
248 //TODO: ibot: maybe decoding qbytearray to unicode in io_layer?
249 QString result = decoder->toUnicode(&s[i],1);
250 int reslen = result.length();
251 for (int j = 0; j < reslen; j++)
252 onRcvChar(result[j].unicode());
253 if (s[i] == '\n') bulkNewline();
254 }
255 bulkEnd();
256}
257
258// Selection --------------------------------------------------------------- --
259
260void EmulationLayer::onSelectionBegin(const int x, const int y) {
261 if (!connected) return;
262 scr->setSelBeginXY(x,y);
263 showBulk();
264}
265
266void EmulationLayer::onSelectionExtend(const int x, const int y) {
267 if (!connected) return;
268 scr->setSelExtentXY(x,y);
269 showBulk();
270}
271
272void EmulationLayer::setSelection(const BOOL preserve_line_breaks) {
273 if (!connected) return;
274 QString t = scr->getSelText(preserve_line_breaks);
275 if (!t.isNull()) gui->setSelection(t);
276}
277
278void EmulationLayer::clearSelection() {
279 if (!connected) return;
280 scr->clearSelection();
281 showBulk();
282}
283
284// Refreshing -------------------------------------------------------------- --
285
286#define BULK_TIMEOUT 20
287
288/*!
289 called when \n comes in. Evtl. triggers showBulk at endBulk
290*/
291
292void EmulationLayer::bulkNewline()
293{
294 bulk_nlcnt += 1;
295 bulk_incnt = 0; // reset bulk counter since `nl' rule applies
296}
297
298/*!
299*/
300
301void EmulationLayer::showBulk()
302{
303 bulk_nlcnt = 0; // reset bulk newline counter
304 bulk_incnt = 0; // reset bulk counter
305 if (connected)
306 {
307 ca* image = scr->getCookedImage(); // get the image
308 gui->setImage(image,
309 scr->getLines(),
310 scr->getColumns()); // actual refresh
311 free(image);
312 //FIXME: check that we do not trigger other draw event here.
313 gui->setScroll(scr->getHistCursor(),scr->getHistLines());
314 }
315}
316
317void EmulationLayer::bulkStart()
318{
319 if (bulk_timer.isActive()) bulk_timer.stop();
320}
321
322void EmulationLayer::bulkEnd()
323{
324 if ( bulk_nlcnt > gui->Lines() || bulk_incnt > 20 )
325 showBulk(); // resets bulk_??cnt to 0, too.
326 else
327 bulk_timer.start(BULK_TIMEOUT,TRUE);
328}
329
330void EmulationLayer::setConnect(bool c)
331{
332 connected = c;
333 if ( connected)
334 {
335 onImageSizeChange(gui->Lines(), gui->Columns());
336 showBulk();
337 }
338 else
339 {
340 scr->clearSelection();
341 }
342}
343
344// ---------------------------------------------------------------------------
345
346/*! triggered by image size change of the TEWidget `gui'.
347
348 This event is simply propagated to the attached screens
349 and to the related serial line.
350*/
351
352void EmulationLayer::onImageSizeChange(int lines, int columns)
353{
354 if (!connected) return;
355 screen[0]->resizeImage(lines,columns);
356 screen[1]->resizeImage(lines,columns);
357 showBulk();
358 emit ImageSizeChanged(lines,columns); // propagate event to serial line
359}
360
361void EmulationLayer::onHistoryCursorChange(int cursor)
362{
363 if (!connected) return;
364 scr->setHistCursor(cursor);
365 showBulk();
366}
367
368void EmulationLayer::setColumns(int columns)
369{
370 //FIXME: this goes strange ways.
371 // Can we put this straight or explain it at least?
372 emit changeColumns(columns);
373}