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