Mercurial > hg > octave-thorsten
comparison gui/qtermwidget/lib/Emulation.cpp @ 14240:a9992bc3c3f7 gui
GUI: Added qtermwidget snapshot as a subproject to build as a library that links with Octave GUI.
author | Jacob Dawid <jacob.dawid@googlemail.com> |
---|---|
date | Sat, 21 Jan 2012 11:26:36 +0100 (2012-01-21) |
parents | fd14634f9c1e |
children |
comparison
equal
deleted
inserted
replaced
14239:7ecaa8a66d5a | 14240:a9992bc3c3f7 |
---|---|
1 /* | |
2 This file is part of Konsole, an X terminal. | |
3 | |
4 Copyright (C) 2007 Robert Knight <robertknight@gmail.com> | |
5 Copyright (C) 1997,1998 by Lars Doelle <lars.doelle@on-line.de> | |
6 Copyright (C) 1996 by Matthias Ettrich <ettrich@kde.org> | |
7 | |
8 Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008 | |
9 | |
10 This program is free software; you can redistribute it and/or modify | |
11 it under the terms of the GNU General Public License as published by | |
12 the Free Software Foundation; either version 2 of the License, or | |
13 (at your option) any later version. | |
14 | |
15 This program is distributed in the hope that it will be useful, | |
16 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
18 GNU General Public License for more details. | |
19 | |
20 You should have received a copy of the GNU General Public License | |
21 along with this program; if not, write to the Free Software | |
22 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | |
23 02110-1301 USA. | |
24 */ | |
25 | |
26 // Own | |
27 #include "Emulation.h" | |
28 | |
29 // System | |
30 #include <assert.h> | |
31 #include <stdio.h> | |
32 #include <stdlib.h> | |
33 #include <unistd.h> | |
34 | |
35 // Qt | |
36 #include <QtGui/QApplication> | |
37 #include <QtGui/QClipboard> | |
38 #include <QtCore/QHash> | |
39 #include <QtGui/QKeyEvent> | |
40 #include <QtCore/QRegExp> | |
41 #include <QtCore/QTextStream> | |
42 #include <QtCore/QThread> | |
43 | |
44 #include <QtCore/QTime> | |
45 | |
46 // Konsole | |
47 #include "KeyboardTranslator.h" | |
48 #include "Screen.h" | |
49 #include "TerminalCharacterDecoder.h" | |
50 #include "ScreenWindow.h" | |
51 | |
52 using namespace Konsole; | |
53 | |
54 /* ------------------------------------------------------------------------- */ | |
55 /* */ | |
56 /* Emulation */ | |
57 /* */ | |
58 /* ------------------------------------------------------------------------- */ | |
59 | |
60 //#define CNTL(c) ((c)-'@') | |
61 | |
62 /*! | |
63 */ | |
64 | |
65 Emulation::Emulation() : | |
66 _currentScreen(0), | |
67 _codec(0), | |
68 _decoder(0), | |
69 _keyTranslator(0), | |
70 _usesMouse(false) | |
71 { | |
72 | |
73 // create screens with a default size | |
74 _screen[0] = new Screen(40,80); | |
75 _screen[1] = new Screen(40,80); | |
76 _currentScreen = _screen[0]; | |
77 | |
78 QObject::connect(&_bulkTimer1, SIGNAL(timeout()), this, SLOT(showBulk()) ); | |
79 QObject::connect(&_bulkTimer2, SIGNAL(timeout()), this, SLOT(showBulk()) ); | |
80 | |
81 // listen for mouse status changes | |
82 connect( this , SIGNAL(programUsesMouseChanged(bool)) , | |
83 SLOT(usesMouseChanged(bool)) ); | |
84 } | |
85 | |
86 bool Emulation::programUsesMouse() const | |
87 { | |
88 return _usesMouse; | |
89 } | |
90 | |
91 void Emulation::usesMouseChanged(bool usesMouse) | |
92 { | |
93 _usesMouse = usesMouse; | |
94 } | |
95 | |
96 ScreenWindow* Emulation::createWindow() | |
97 { | |
98 ScreenWindow* window = new ScreenWindow(); | |
99 window->setScreen(_currentScreen); | |
100 _windows << window; | |
101 | |
102 connect(window , SIGNAL(selectionChanged()), | |
103 this , SLOT(bufferedUpdate())); | |
104 | |
105 connect(this , SIGNAL(outputChanged()), | |
106 window , SLOT(notifyOutputChanged()) ); | |
107 return window; | |
108 } | |
109 | |
110 /*! | |
111 */ | |
112 | |
113 Emulation::~Emulation() | |
114 { | |
115 QListIterator<ScreenWindow*> windowIter(_windows); | |
116 | |
117 while (windowIter.hasNext()) | |
118 { | |
119 delete windowIter.next(); | |
120 } | |
121 | |
122 delete _screen[0]; | |
123 delete _screen[1]; | |
124 delete _decoder; | |
125 } | |
126 | |
127 /*! change between primary and alternate _screen | |
128 */ | |
129 | |
130 void Emulation::setScreen(int n) | |
131 { | |
132 Screen *old = _currentScreen; | |
133 _currentScreen = _screen[n&1]; | |
134 if (_currentScreen != old) | |
135 { | |
136 old->setBusySelecting(false); | |
137 | |
138 // tell all windows onto this emulation to switch to the newly active _screen | |
139 QListIterator<ScreenWindow*> windowIter(_windows); | |
140 while ( windowIter.hasNext() ) | |
141 { | |
142 windowIter.next()->setScreen(_currentScreen); | |
143 } | |
144 } | |
145 } | |
146 | |
147 void Emulation::clearHistory() | |
148 { | |
149 _screen[0]->setScroll( _screen[0]->getScroll() , false ); | |
150 } | |
151 void Emulation::setHistory(const HistoryType& t) | |
152 { | |
153 _screen[0]->setScroll(t); | |
154 | |
155 showBulk(); | |
156 } | |
157 | |
158 const HistoryType& Emulation::history() | |
159 { | |
160 return _screen[0]->getScroll(); | |
161 } | |
162 | |
163 void Emulation::setCodec(const QTextCodec * qtc) | |
164 { | |
165 Q_ASSERT( qtc ); | |
166 | |
167 _codec = qtc; | |
168 delete _decoder; | |
169 _decoder = _codec->makeDecoder(); | |
170 | |
171 emit useUtf8Request(utf8()); | |
172 } | |
173 | |
174 void Emulation::setCodec(EmulationCodec codec) | |
175 { | |
176 if ( codec == Utf8Codec ) | |
177 setCodec( QTextCodec::codecForName("utf8") ); | |
178 else if ( codec == LocaleCodec ) | |
179 setCodec( QTextCodec::codecForLocale() ); | |
180 } | |
181 | |
182 void Emulation::setKeyBindings(const QString& name) | |
183 { | |
184 _keyTranslator = KeyboardTranslatorManager::instance()->findTranslator(name); | |
185 } | |
186 | |
187 QString Emulation::keyBindings() | |
188 { | |
189 return _keyTranslator->name(); | |
190 } | |
191 | |
192 | |
193 // Interpreting Codes --------------------------------------------------------- | |
194 | |
195 /* | |
196 This section deals with decoding the incoming character stream. | |
197 Decoding means here, that the stream is first separated into `tokens' | |
198 which are then mapped to a `meaning' provided as operations by the | |
199 `Screen' class. | |
200 */ | |
201 | |
202 /*! | |
203 */ | |
204 | |
205 void Emulation::receiveChar(int c) | |
206 // process application unicode input to terminal | |
207 // this is a trivial scanner | |
208 { | |
209 c &= 0xff; | |
210 switch (c) | |
211 { | |
212 case '\b' : _currentScreen->BackSpace(); break; | |
213 case '\t' : _currentScreen->Tabulate(); break; | |
214 case '\n' : _currentScreen->NewLine(); break; | |
215 case '\r' : _currentScreen->Return(); break; | |
216 case 0x07 : emit stateSet(NOTIFYBELL); | |
217 break; | |
218 default : _currentScreen->ShowCharacter(c); break; | |
219 }; | |
220 } | |
221 | |
222 /* ------------------------------------------------------------------------- */ | |
223 /* */ | |
224 /* Keyboard Handling */ | |
225 /* */ | |
226 /* ------------------------------------------------------------------------- */ | |
227 | |
228 /*! | |
229 */ | |
230 | |
231 void Emulation::sendKeyEvent( QKeyEvent* ev ) | |
232 { | |
233 emit stateSet(NOTIFYNORMAL); | |
234 | |
235 if (!ev->text().isEmpty()) | |
236 { // A block of text | |
237 // Note that the text is proper unicode. | |
238 // We should do a conversion here, but since this | |
239 // routine will never be used, we simply emit plain ascii. | |
240 //emit sendBlock(ev->text().toAscii(),ev->text().length()); | |
241 emit sendData(ev->text().toUtf8(),ev->text().length()); | |
242 } | |
243 } | |
244 | |
245 void Emulation::sendString(const char*,int) | |
246 { | |
247 // default implementation does nothing | |
248 } | |
249 | |
250 void Emulation::sendMouseEvent(int /*buttons*/, int /*column*/, int /*row*/, int /*eventType*/) | |
251 { | |
252 // default implementation does nothing | |
253 } | |
254 | |
255 // Unblocking, Byte to Unicode translation --------------------------------- -- | |
256 | |
257 /* | |
258 We are doing code conversion from locale to unicode first. | |
259 TODO: Character composition from the old code. See #96536 | |
260 */ | |
261 | |
262 void Emulation::receiveData(const char* text, int length) | |
263 { | |
264 emit stateSet(NOTIFYACTIVITY); | |
265 | |
266 bufferedUpdate(); | |
267 | |
268 QString unicodeText = _decoder->toUnicode(text,length); | |
269 | |
270 //send characters to terminal emulator | |
271 for (int i=0;i<unicodeText.length();i++) | |
272 { | |
273 receiveChar(unicodeText[i].unicode()); | |
274 } | |
275 | |
276 //look for z-modem indicator | |
277 //-- someone who understands more about z-modems that I do may be able to move | |
278 //this check into the above for loop? | |
279 for (int i=0;i<length;i++) | |
280 { | |
281 if (text[i] == '\030') | |
282 { | |
283 if ((length-i-1 > 3) && (strncmp(text+i+1, "B00", 3) == 0)) | |
284 emit zmodemDetected(); | |
285 } | |
286 } | |
287 } | |
288 | |
289 //OLDER VERSION | |
290 //This version of onRcvBlock was commented out because | |
291 // a) It decoded incoming characters one-by-one, which is slow in the current version of Qt (4.2 tech preview) | |
292 // b) It messed up decoding of non-ASCII characters, with the result that (for example) chinese characters | |
293 // were not printed properly. | |
294 // | |
295 //There is something about stopping the _decoder if "we get a control code halfway a multi-byte sequence" (see below) | |
296 //which hasn't been ported into the newer function (above). Hopefully someone who understands this better | |
297 //can find an alternative way of handling the check. | |
298 | |
299 | |
300 /*void Emulation::onRcvBlock(const char *s, int len) | |
301 { | |
302 emit notifySessionState(NOTIFYACTIVITY); | |
303 | |
304 bufferedUpdate(); | |
305 for (int i = 0; i < len; i++) | |
306 { | |
307 | |
308 QString result = _decoder->toUnicode(&s[i],1); | |
309 int reslen = result.length(); | |
310 | |
311 // If we get a control code halfway a multi-byte sequence | |
312 // we flush the _decoder and continue with the control code. | |
313 if ((s[i] < 32) && (s[i] > 0)) | |
314 { | |
315 // Flush _decoder | |
316 while(!result.length()) | |
317 result = _decoder->toUnicode(&s[i],1); | |
318 reslen = 1; | |
319 result.resize(reslen); | |
320 result[0] = QChar(s[i]); | |
321 } | |
322 | |
323 for (int j = 0; j < reslen; j++) | |
324 { | |
325 if (result[j].characterategory() == QChar::Mark_NonSpacing) | |
326 _currentScreen->compose(result.mid(j,1)); | |
327 else | |
328 onRcvChar(result[j].unicode()); | |
329 } | |
330 if (s[i] == '\030') | |
331 { | |
332 if ((len-i-1 > 3) && (strncmp(s+i+1, "B00", 3) == 0)) | |
333 emit zmodemDetected(); | |
334 } | |
335 } | |
336 }*/ | |
337 | |
338 // Selection --------------------------------------------------------------- -- | |
339 | |
340 #if 0 | |
341 void Emulation::onSelectionBegin(const int x, const int y, const bool columnmode) { | |
342 if (!connected) return; | |
343 _currentScreen->setSelectionStart( x,y,columnmode); | |
344 showBulk(); | |
345 } | |
346 | |
347 void Emulation::onSelectionExtend(const int x, const int y) { | |
348 if (!connected) return; | |
349 _currentScreen->setSelectionEnd(x,y); | |
350 showBulk(); | |
351 } | |
352 | |
353 void Emulation::setSelection(const bool preserve_line_breaks) { | |
354 if (!connected) return; | |
355 QString t = _currentScreen->selectedText(preserve_line_breaks); | |
356 if (!t.isNull()) | |
357 { | |
358 QListIterator< TerminalDisplay* > viewIter(_views); | |
359 | |
360 while (viewIter.hasNext()) | |
361 viewIter.next()->setSelection(t); | |
362 } | |
363 } | |
364 | |
365 void Emulation::testIsSelected(const int x, const int y, bool &selected) | |
366 { | |
367 if (!connected) return; | |
368 selected=_currentScreen->isSelected(x,y); | |
369 } | |
370 | |
371 void Emulation::clearSelection() { | |
372 if (!connected) return; | |
373 _currentScreen->clearSelection(); | |
374 showBulk(); | |
375 } | |
376 | |
377 #endif | |
378 | |
379 void Emulation::writeToStream( TerminalCharacterDecoder* _decoder , | |
380 int startLine , | |
381 int endLine) | |
382 { | |
383 _currentScreen->writeToStream(_decoder,startLine,endLine); | |
384 } | |
385 | |
386 int Emulation::lineCount() | |
387 { | |
388 // sum number of lines currently on _screen plus number of lines in history | |
389 return _currentScreen->getLines() + _currentScreen->getHistLines(); | |
390 } | |
391 | |
392 // Refreshing -------------------------------------------------------------- -- | |
393 | |
394 #define BULK_TIMEOUT1 10 | |
395 #define BULK_TIMEOUT2 40 | |
396 | |
397 /*! | |
398 */ | |
399 void Emulation::showBulk() | |
400 { | |
401 _bulkTimer1.stop(); | |
402 _bulkTimer2.stop(); | |
403 | |
404 emit outputChanged(); | |
405 | |
406 _currentScreen->resetScrolledLines(); | |
407 _currentScreen->resetDroppedLines(); | |
408 } | |
409 | |
410 void Emulation::bufferedUpdate() | |
411 { | |
412 _bulkTimer1.setSingleShot(true); | |
413 _bulkTimer1.start(BULK_TIMEOUT1); | |
414 if (!_bulkTimer2.isActive()) | |
415 { | |
416 _bulkTimer2.setSingleShot(true); | |
417 _bulkTimer2.start(BULK_TIMEOUT2); | |
418 } | |
419 } | |
420 | |
421 char Emulation::getErase() const | |
422 { | |
423 return '\b'; | |
424 } | |
425 | |
426 void Emulation::setImageSize(int lines, int columns) | |
427 { | |
428 //kDebug() << "Resizing image to: " << lines << "by" << columns << QTime::currentTime().msec(); | |
429 Q_ASSERT( lines > 0 ); | |
430 Q_ASSERT( columns > 0 ); | |
431 | |
432 _screen[0]->resizeImage(lines,columns); | |
433 _screen[1]->resizeImage(lines,columns); | |
434 | |
435 emit imageSizeChanged(lines,columns); | |
436 | |
437 bufferedUpdate(); | |
438 } | |
439 | |
440 QSize Emulation::imageSize() | |
441 { | |
442 return QSize(_currentScreen->getColumns(), _currentScreen->getLines()); | |
443 } | |
444 | |
445 ushort ExtendedCharTable::extendedCharHash(ushort* unicodePoints , ushort length) const | |
446 { | |
447 ushort hash = 0; | |
448 for ( ushort i = 0 ; i < length ; i++ ) | |
449 { | |
450 hash = 31*hash + unicodePoints[i]; | |
451 } | |
452 return hash; | |
453 } | |
454 bool ExtendedCharTable::extendedCharMatch(ushort hash , ushort* unicodePoints , ushort length) const | |
455 { | |
456 ushort* entry = extendedCharTable[hash]; | |
457 | |
458 // compare given length with stored sequence length ( given as the first ushort in the | |
459 // stored buffer ) | |
460 if ( entry == 0 || entry[0] != length ) | |
461 return false; | |
462 // if the lengths match, each character must be checked. the stored buffer starts at | |
463 // entry[1] | |
464 for ( int i = 0 ; i < length ; i++ ) | |
465 { | |
466 if ( entry[i+1] != unicodePoints[i] ) | |
467 return false; | |
468 } | |
469 return true; | |
470 } | |
471 ushort ExtendedCharTable::createExtendedChar(ushort* unicodePoints , ushort length) | |
472 { | |
473 // look for this sequence of points in the table | |
474 ushort hash = extendedCharHash(unicodePoints,length); | |
475 | |
476 // check existing entry for match | |
477 while ( extendedCharTable.contains(hash) ) | |
478 { | |
479 if ( extendedCharMatch(hash,unicodePoints,length) ) | |
480 { | |
481 // this sequence already has an entry in the table, | |
482 // return its hash | |
483 return hash; | |
484 } | |
485 else | |
486 { | |
487 // if hash is already used by another, different sequence of unicode character | |
488 // points then try next hash | |
489 hash++; | |
490 } | |
491 } | |
492 | |
493 | |
494 // add the new sequence to the table and | |
495 // return that index | |
496 ushort* buffer = new ushort[length+1]; | |
497 buffer[0] = length; | |
498 for ( int i = 0 ; i < length ; i++ ) | |
499 buffer[i+1] = unicodePoints[i]; | |
500 | |
501 extendedCharTable.insert(hash,buffer); | |
502 | |
503 return hash; | |
504 } | |
505 | |
506 ushort* ExtendedCharTable::lookupExtendedChar(ushort hash , ushort& length) const | |
507 { | |
508 // lookup index in table and if found, set the length | |
509 // argument and return a pointer to the character sequence | |
510 | |
511 ushort* buffer = extendedCharTable[hash]; | |
512 if ( buffer ) | |
513 { | |
514 length = buffer[0]; | |
515 return buffer+1; | |
516 } | |
517 else | |
518 { | |
519 length = 0; | |
520 return 0; | |
521 } | |
522 } | |
523 | |
524 ExtendedCharTable::ExtendedCharTable() | |
525 { | |
526 } | |
527 ExtendedCharTable::~ExtendedCharTable() | |
528 { | |
529 // free all allocated character buffers | |
530 QHashIterator<ushort,ushort*> iter(extendedCharTable); | |
531 while ( iter.hasNext() ) | |
532 { | |
533 iter.next(); | |
534 delete[] iter.value(); | |
535 } | |
536 } | |
537 | |
538 // global instance | |
539 ExtendedCharTable ExtendedCharTable::instance; | |
540 | |
541 | |
542 //#include "moc_Emulation.cpp" | |
543 |