source: ogBrowser-Git/qtermwidget/src/Emulation.cpp

qndtest
Last change on this file was 8ab4781, checked in by adelcastillo <adelcastillo@…>, 15 years ago

Cambiando a qmake de nuevo.

git-svn-id: https://opengnsys.es/svn/trunk@518 a21b9725-9963-47de-94b9-378ad31fedc9

  • Property mode set to 100644
File size: 13.8 KB
Line 
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
52using namespace Konsole;
53
54/* ------------------------------------------------------------------------- */
55/*                                                                           */
56/*                               Emulation                                  */
57/*                                                                           */
58/* ------------------------------------------------------------------------- */
59
60//#define CNTL(c) ((c)-'@')
61
62/*!
63*/
64
65Emulation::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
86bool Emulation::programUsesMouse() const
87{
88    return _usesMouse;
89}
90
91void Emulation::usesMouseChanged(bool usesMouse)
92{
93    _usesMouse = usesMouse;
94}
95
96ScreenWindow* 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
113Emulation::~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
130void 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
147void Emulation::clearHistory()
148{
149    _screen[0]->setScroll( _screen[0]->getScroll() , false );
150}
151void Emulation::setHistory(const HistoryType& t)
152{
153  _screen[0]->setScroll(t);
154
155  showBulk();
156}
157
158const HistoryType& Emulation::history()
159{
160  return _screen[0]->getScroll();
161}
162
163void 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
174void 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
182void Emulation::setKeyBindings(const QString& name)
183{
184  _keyTranslator = KeyboardTranslatorManager::instance()->findTranslator(name);
185}
186
187QString 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
205void 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
231void 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
245void Emulation::sendString(const char*,int)
246{
247    // default implementation does nothing
248}
249
250void 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.
259TODO: Character composition from the old code.  See #96536
260*/
261
262void 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
341void 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
347void Emulation::onSelectionExtend(const int x, const int y) {
348  if (!connected) return;
349  _currentScreen->setSelectionEnd(x,y);
350  showBulk();
351}
352
353void 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
365void Emulation::testIsSelected(const int x, const int y, bool &selected)
366{
367  if (!connected) return;
368  selected=_currentScreen->isSelected(x,y);
369}
370
371void Emulation::clearSelection() {
372  if (!connected) return;
373  _currentScreen->clearSelection();
374  showBulk();
375}
376
377#endif
378
379void Emulation::writeToStream( TerminalCharacterDecoder* _decoder , 
380                               int startLine ,
381                               int endLine) 
382{
383  _currentScreen->writeToStream(_decoder,startLine,endLine);
384}
385
386int 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*/
399void Emulation::showBulk()
400{
401    _bulkTimer1.stop();
402    _bulkTimer2.stop();
403
404    emit outputChanged();
405
406    _currentScreen->resetScrolledLines();
407    _currentScreen->resetDroppedLines();
408}
409
410void 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
421char Emulation::getErase() const
422{
423  return '\b';
424}
425
426void 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
440QSize Emulation::imageSize()
441{
442  return QSize(_currentScreen->getColumns(), _currentScreen->getLines());
443}
444
445ushort 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}
454bool 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}
471ushort 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
506ushort* 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
524ExtendedCharTable::ExtendedCharTable()
525{
526}
527ExtendedCharTable::~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
539ExtendedCharTable ExtendedCharTable::instance;
540
541
542//#include "moc_Emulation.cpp"
543
Note: See TracBrowser for help on using the repository browser.