File: | libgui/qterminal/libqterminal/unix/Emulation.cpp |
Location: | line 156, column 14 |
Description: | Called C++ object pointer is null |
1 | /* | |||
2 | This file is part of Konsole, an X terminal. | |||
3 | ||||
4 | Copyright (C) 2007, 2013 Robert Knight <robertknight@gmail.com> | |||
5 | Copyright (C) 1997,1998 by Lars Doelle <lars.doelle@on-line.de> | |||
6 | Copyright (C) 1996, 2013 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 "unix/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 <QApplication> | |||
37 | #include <QClipboard> | |||
38 | #include <QtCore/QHash> | |||
39 | #include <QKeyEvent> | |||
40 | #include <QtCore/QRegExp> | |||
41 | #include <QtCore/QTextStream> | |||
42 | #include <QtCore/QThread> | |||
43 | ||||
44 | #include <QtCore/QTime> | |||
45 | ||||
46 | // Konsole | |||
47 | #include "unix/KeyboardTranslator.h" | |||
48 | #include "unix/Screen.h" | |||
49 | #include "unix/TerminalCharacterDecoder.h" | |||
50 | #include "unix/ScreenWindow.h" | |||
51 | ||||
52 | Emulation::Emulation() : | |||
53 | _currentScreen(0), | |||
54 | _codec(0), | |||
55 | _decoder(0), | |||
56 | _keyTranslator(0), | |||
57 | _usesMouse(false) | |||
58 | { | |||
59 | ||||
60 | // create screens with a default size | |||
61 | _screen[0] = new Screen(40,80); | |||
62 | _screen[1] = new Screen(40,80); | |||
63 | _currentScreen = _screen[0]; | |||
64 | ||||
65 | QObject::connect(&_bulkTimer1, SIGNAL(timeout())qFlagLocation("2""timeout()" "\0" "qterminal/libqterminal/unix/Emulation.cpp" ":" "65"), this, SLOT(showBulk())qFlagLocation("1""showBulk()" "\0" "qterminal/libqterminal/unix/Emulation.cpp" ":" "65") ); | |||
66 | QObject::connect(&_bulkTimer2, SIGNAL(timeout())qFlagLocation("2""timeout()" "\0" "qterminal/libqterminal/unix/Emulation.cpp" ":" "66"), this, SLOT(showBulk())qFlagLocation("1""showBulk()" "\0" "qterminal/libqterminal/unix/Emulation.cpp" ":" "66") ); | |||
67 | ||||
68 | // listen for mouse status changes | |||
69 | connect( this , SIGNAL(programUsesMouseChanged(bool))qFlagLocation("2""programUsesMouseChanged(bool)" "\0" "qterminal/libqterminal/unix/Emulation.cpp" ":" "69") , | |||
70 | SLOT(usesMouseChanged(bool))qFlagLocation("1""usesMouseChanged(bool)" "\0" "qterminal/libqterminal/unix/Emulation.cpp" ":" "70") ); | |||
71 | } | |||
72 | ||||
73 | bool Emulation::programUsesMouse() const | |||
74 | { | |||
75 | return _usesMouse; | |||
76 | } | |||
77 | ||||
78 | void Emulation::usesMouseChanged(bool usesMouse) | |||
79 | { | |||
80 | _usesMouse = usesMouse; | |||
81 | } | |||
82 | ||||
83 | ScreenWindow* Emulation::createWindow() | |||
84 | { | |||
85 | ScreenWindow* window = new ScreenWindow(); | |||
86 | window->setScreen(_currentScreen); | |||
87 | _windows << window; | |||
88 | ||||
89 | connect(window , SIGNAL(selectionChanged())qFlagLocation("2""selectionChanged()" "\0" "qterminal/libqterminal/unix/Emulation.cpp" ":" "89"), | |||
90 | this , SLOT(bufferedUpdate())qFlagLocation("1""bufferedUpdate()" "\0" "qterminal/libqterminal/unix/Emulation.cpp" ":" "90")); | |||
91 | ||||
92 | connect(this , SIGNAL(outputChanged())qFlagLocation("2""outputChanged()" "\0" "qterminal/libqterminal/unix/Emulation.cpp" ":" "92"), | |||
93 | window , SLOT(notifyOutputChanged())qFlagLocation("1""notifyOutputChanged()" "\0" "qterminal/libqterminal/unix/Emulation.cpp" ":" "93") ); | |||
94 | return window; | |||
95 | } | |||
96 | ||||
97 | /*! | |||
98 | */ | |||
99 | ||||
100 | Emulation::~Emulation() | |||
101 | { | |||
102 | QListIterator<ScreenWindow*> windowIter(_windows); | |||
103 | ||||
104 | while (windowIter.hasNext()) | |||
105 | { | |||
106 | delete windowIter.next(); | |||
107 | } | |||
108 | ||||
109 | delete _screen[0]; | |||
110 | delete _screen[1]; | |||
111 | delete _decoder; | |||
112 | } | |||
113 | ||||
114 | /*! change between primary and alternate _screen | |||
115 | */ | |||
116 | ||||
117 | void Emulation::setScreen(int n) | |||
118 | { | |||
119 | Screen *old = _currentScreen; | |||
120 | _currentScreen = _screen[n&1]; | |||
121 | if (_currentScreen != old) | |||
122 | { | |||
123 | old->setBusySelecting(false); | |||
124 | ||||
125 | // tell all windows onto this emulation to switch to the newly active _screen | |||
126 | QListIterator<ScreenWindow*> windowIter(_windows); | |||
127 | while ( windowIter.hasNext() ) | |||
128 | { | |||
129 | windowIter.next()->setScreen(_currentScreen); | |||
130 | } | |||
131 | } | |||
132 | } | |||
133 | ||||
134 | void Emulation::clearHistory() | |||
135 | { | |||
136 | _screen[0]->setScroll( _screen[0]->getScroll() , false ); | |||
137 | } | |||
138 | void Emulation::setHistory(const HistoryType& t) | |||
139 | { | |||
140 | _screen[0]->setScroll(t); | |||
141 | ||||
142 | showBulk(); | |||
143 | } | |||
144 | ||||
145 | const HistoryType& Emulation::history() | |||
146 | { | |||
147 | return _screen[0]->getScroll(); | |||
148 | } | |||
149 | ||||
150 | void Emulation::setCodec(const QTextCodec * qtc) | |||
151 | { | |||
152 | Q_ASSERT( qtc )((!(qtc)) ? qt_assert("qtc","qterminal/libqterminal/unix/Emulation.cpp" ,152) : qt_noop()); | |||
153 | ||||
154 | _codec = qtc; | |||
155 | delete _decoder; | |||
156 | _decoder = _codec->makeDecoder(); | |||
| ||||
157 | ||||
158 | emit useUtf8Request(utf8()); | |||
159 | } | |||
160 | ||||
161 | void Emulation::setCodec(EmulationCodec codec) | |||
162 | { | |||
163 | if ( codec == Utf8Codec ) | |||
| ||||
164 | setCodec( QTextCodec::codecForName("utf8") ); | |||
165 | else if ( codec == LocaleCodec ) | |||
166 | setCodec( QTextCodec::codecForLocale() ); | |||
167 | } | |||
168 | ||||
169 | void Emulation::setKeyBindings(const QString& name) | |||
170 | { | |||
171 | _keyTranslator = KeyboardTranslatorManager::instance()->findTranslator(name); | |||
172 | } | |||
173 | ||||
174 | QString Emulation::keyBindings() | |||
175 | { | |||
176 | return _keyTranslator->name(); | |||
177 | } | |||
178 | ||||
179 | ||||
180 | // Interpreting Codes --------------------------------------------------------- | |||
181 | ||||
182 | /* | |||
183 | This section deals with decoding the incoming character stream. | |||
184 | Decoding means here, that the stream is first separated into `tokens' | |||
185 | which are then mapped to a `meaning' provided as operations by the | |||
186 | `Screen' class. | |||
187 | */ | |||
188 | ||||
189 | /*! | |||
190 | */ | |||
191 | ||||
192 | void Emulation::receiveChar(int c) | |||
193 | // process application unicode input to terminal | |||
194 | // this is a trivial scanner | |||
195 | { | |||
196 | c &= 0xff; | |||
197 | switch (c) | |||
198 | { | |||
199 | case '\b' : _currentScreen->BackSpace(); break; | |||
200 | case '\t' : _currentScreen->Tabulate(); break; | |||
201 | case '\n' : _currentScreen->NewLine(); break; | |||
202 | case '\r' : _currentScreen->Return(); break; | |||
203 | case 0x07 : emit stateSet(NOTIFYBELL); | |||
204 | break; | |||
205 | default : _currentScreen->ShowCharacter(c); break; | |||
206 | }; | |||
207 | } | |||
208 | ||||
209 | /* ------------------------------------------------------------------------- */ | |||
210 | /* */ | |||
211 | /* Keyboard Handling */ | |||
212 | /* */ | |||
213 | /* ------------------------------------------------------------------------- */ | |||
214 | ||||
215 | /*! | |||
216 | */ | |||
217 | ||||
218 | void Emulation::sendKeyEvent( QKeyEvent* ev ) | |||
219 | { | |||
220 | emit stateSet(NOTIFYNORMAL); | |||
221 | ||||
222 | if (!ev->text().isEmpty()) | |||
223 | { // A block of text | |||
224 | // Note that the text is proper unicode. | |||
225 | // We should do a conversion here, but since this | |||
226 | // routine will never be used, we simply emit plain ascii. | |||
227 | //emit sendBlock(ev->text().toAscii(),ev->text().length()); | |||
228 | emit sendData(ev->text().toUtf8(),ev->text().length()); | |||
229 | } | |||
230 | } | |||
231 | ||||
232 | void Emulation::sendString(const char*,int) | |||
233 | { | |||
234 | // default implementation does nothing | |||
235 | } | |||
236 | ||||
237 | void Emulation::sendMouseEvent(int /*buttons*/, int /*column*/, int /*row*/, int /*eventType*/) | |||
238 | { | |||
239 | // default implementation does nothing | |||
240 | } | |||
241 | ||||
242 | // Unblocking, Byte to Unicode translation --------------------------------- -- | |||
243 | ||||
244 | /* | |||
245 | We are doing code conversion from locale to unicode first. | |||
246 | TODO: Character composition from the old code. See #96536 | |||
247 | */ | |||
248 | ||||
249 | void Emulation::receiveData(const char* text, int length) | |||
250 | { | |||
251 | emit stateSet(NOTIFYACTIVITY); | |||
252 | ||||
253 | bufferedUpdate(); | |||
254 | ||||
255 | QString unicodeText = _decoder->toUnicode(text,length); | |||
256 | ||||
257 | //send characters to terminal emulator | |||
258 | for (int i=0;i<unicodeText.length();i++) | |||
259 | { | |||
260 | receiveChar(unicodeText[i].unicode()); | |||
261 | } | |||
262 | } | |||
263 | ||||
264 | // Selection --------------------------------------------------------------- -- | |||
265 | ||||
266 | void Emulation::writeToStream( TerminalCharacterDecoder* _decoder , | |||
267 | int startLine , | |||
268 | int endLine) | |||
269 | { | |||
270 | _currentScreen->writeToStream(_decoder,startLine,endLine); | |||
271 | } | |||
272 | ||||
273 | int Emulation::lineCount() | |||
274 | { | |||
275 | // sum number of lines currently on _screen plus number of lines in history | |||
276 | return _currentScreen->getLines() + _currentScreen->getHistLines(); | |||
277 | } | |||
278 | ||||
279 | // Refreshing -------------------------------------------------------------- -- | |||
280 | ||||
281 | #define BULK_TIMEOUT110 10 | |||
282 | #define BULK_TIMEOUT240 40 | |||
283 | ||||
284 | /*! | |||
285 | */ | |||
286 | void Emulation::showBulk() | |||
287 | { | |||
288 | _bulkTimer1.stop(); | |||
289 | _bulkTimer2.stop(); | |||
290 | ||||
291 | emit outputChanged(); | |||
292 | ||||
293 | _currentScreen->resetScrolledLines(); | |||
294 | _currentScreen->resetDroppedLines(); | |||
295 | } | |||
296 | ||||
297 | void Emulation::bufferedUpdate() | |||
298 | { | |||
299 | _bulkTimer1.setSingleShot(true); | |||
300 | _bulkTimer1.start(BULK_TIMEOUT110); | |||
301 | if (!_bulkTimer2.isActive()) | |||
302 | { | |||
303 | _bulkTimer2.setSingleShot(true); | |||
304 | _bulkTimer2.start(BULK_TIMEOUT240); | |||
305 | } | |||
306 | } | |||
307 | ||||
308 | char Emulation::getErase() const | |||
309 | { | |||
310 | return '\b'; | |||
311 | } | |||
312 | ||||
313 | void Emulation::setImageSize(int lines, int columns) | |||
314 | { | |||
315 | //kDebug() << "Resizing image to: " << lines << "by" << columns << QTime::currentTime().msec(); | |||
316 | Q_ASSERT( lines > 0 )((!(lines > 0)) ? qt_assert("lines > 0","qterminal/libqterminal/unix/Emulation.cpp" ,316) : qt_noop()); | |||
317 | Q_ASSERT( columns > 0 )((!(columns > 0)) ? qt_assert("columns > 0","qterminal/libqterminal/unix/Emulation.cpp" ,317) : qt_noop()); | |||
318 | ||||
319 | _screen[0]->resizeImage(lines,columns); | |||
320 | _screen[1]->resizeImage(lines,columns); | |||
321 | ||||
322 | emit imageSizeChanged(lines,columns); | |||
323 | ||||
324 | bufferedUpdate(); | |||
325 | } | |||
326 | ||||
327 | QSize Emulation::imageSize() | |||
328 | { | |||
329 | return QSize(_currentScreen->getColumns(), _currentScreen->getLines()); | |||
330 | } | |||
331 | ||||
332 | ushort ExtendedCharTable::extendedCharHash(ushort* unicodePoints , ushort length) const | |||
333 | { | |||
334 | ushort hash = 0; | |||
335 | for ( ushort i = 0 ; i < length ; i++ ) | |||
336 | { | |||
337 | hash = 31*hash + unicodePoints[i]; | |||
338 | } | |||
339 | return hash; | |||
340 | } | |||
341 | bool ExtendedCharTable::extendedCharMatch(ushort hash , ushort* unicodePoints , ushort length) const | |||
342 | { | |||
343 | ushort* entry = extendedCharTable[hash]; | |||
344 | ||||
345 | // compare given length with stored sequence length ( given as the first ushort in the | |||
346 | // stored buffer ) | |||
347 | if ( entry == 0 || entry[0] != length ) | |||
348 | return false; | |||
349 | // if the lengths match, each character must be checked. the stored buffer starts at | |||
350 | // entry[1] | |||
351 | for ( int i = 0 ; i < length ; i++ ) | |||
352 | { | |||
353 | if ( entry[i+1] != unicodePoints[i] ) | |||
354 | return false; | |||
355 | } | |||
356 | return true; | |||
357 | } | |||
358 | ushort ExtendedCharTable::createExtendedChar(ushort* unicodePoints , ushort length) | |||
359 | { | |||
360 | // look for this sequence of points in the table | |||
361 | ushort hash = extendedCharHash(unicodePoints,length); | |||
362 | ||||
363 | // check existing entry for match | |||
364 | while ( extendedCharTable.contains(hash) ) | |||
365 | { | |||
366 | if ( extendedCharMatch(hash,unicodePoints,length) ) | |||
367 | { | |||
368 | // this sequence already has an entry in the table, | |||
369 | // return its hash | |||
370 | return hash; | |||
371 | } | |||
372 | else | |||
373 | { | |||
374 | // if hash is already used by another, different sequence of unicode character | |||
375 | // points then try next hash | |||
376 | hash++; | |||
377 | } | |||
378 | } | |||
379 | ||||
380 | ||||
381 | // add the new sequence to the table and | |||
382 | // return that index | |||
383 | ushort* buffer = new ushort[length+1]; | |||
384 | buffer[0] = length; | |||
385 | for ( int i = 0 ; i < length ; i++ ) | |||
386 | buffer[i+1] = unicodePoints[i]; | |||
387 | ||||
388 | extendedCharTable.insert(hash,buffer); | |||
389 | ||||
390 | return hash; | |||
391 | } | |||
392 | ||||
393 | ushort* ExtendedCharTable::lookupExtendedChar(ushort hash , ushort& length) const | |||
394 | { | |||
395 | // lookup index in table and if found, set the length | |||
396 | // argument and return a pointer to the character sequence | |||
397 | ||||
398 | ushort* buffer = extendedCharTable[hash]; | |||
399 | if ( buffer ) | |||
400 | { | |||
401 | length = buffer[0]; | |||
402 | return buffer+1; | |||
403 | } | |||
404 | else | |||
405 | { | |||
406 | length = 0; | |||
407 | return 0; | |||
408 | } | |||
409 | } | |||
410 | ||||
411 | ExtendedCharTable::ExtendedCharTable() | |||
412 | { | |||
413 | } | |||
414 | ExtendedCharTable::~ExtendedCharTable() | |||
415 | { | |||
416 | // free all allocated character buffers | |||
417 | QHashIterator<ushort,ushort*> iter(extendedCharTable); | |||
418 | while ( iter.hasNext() ) | |||
419 | { | |||
420 | iter.next(); | |||
421 | delete[] iter.value(); | |||
422 | } | |||
423 | } | |||
424 | ||||
425 | // global instance | |||
426 | ExtendedCharTable ExtendedCharTable::instance; |