comparison libqterminal/unix/TerminalModel.cpp @ 15651:845cebf281aa

Added files of QConsole.
author Jacob Dawid <jacob.dawid@googlemail.com>
date Mon, 30 Jan 2012 11:23:13 +0100
parents
children 35c891dce299
comparison
equal deleted inserted replaced
15650:ba360324035e 15651:845cebf281aa
1 /*
2 This file is part of Konsole
3
4 Copyright (C) 2006-2007 by Robert Knight <robertknight@gmail.com>
5 Copyright (C) 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
6
7 Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
8 Copyright (C) 2012 Jacob Dawid <jacob.dawid@googlemail.com>
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 "TerminalModel.h"
28
29 // Standard
30 #include <assert.h>
31 #include <stdlib.h>
32
33 // Qt
34 #include <QtGui/QApplication>
35 #include <QtCore/QByteRef>
36 #include <QtCore/QDir>
37 #include <QtCore/QFile>
38 #include <QtCore/QRegExp>
39 #include <QtCore/QStringList>
40 #include <QtCore>
41
42 #include "TerminalView.h"
43 #include "Vt102Emulation.h"
44
45 TerminalModel::TerminalModel(KPty *kpty) :
46 _shellProcess(0)
47 , _emulation(0)
48 , _monitorActivity(false)
49 , _monitorSilence(false)
50 , _notifiedActivity(false)
51 , _autoClose(true)
52 , _wantedClose(false)
53 , _silenceSeconds(10)
54 , _addToUtmp(false)
55 , _fullScripting(false)
56 , _hasDarkBackground(false)
57 {
58 _kpty = kpty;
59
60 //create emulation backend
61 _emulation = new Vt102Emulation();
62 connect( _emulation, SIGNAL( stateSet(int) ),
63 this, SLOT( activityStateSet(int) ) );
64 connect( _emulation, SIGNAL( changeTabTextColorRequest( int ) ),
65 this, SIGNAL( changeTabTextColorRequest( int ) ) );
66 connect( _emulation, SIGNAL(profileChangeCommandReceived(const QString&)),
67 this, SIGNAL( profileChangeCommandReceived(const QString&)) );
68 // TODO
69 // connect( _emulation,SIGNAL(imageSizeChanged(int,int)) , this ,
70 // SLOT(onEmulationSizeChange(int,int)) );
71
72 _selfListener = new SelfListener(kpty->masterFd());
73 _selfListener->start();
74 connect( _selfListener, SIGNAL(recvData(const char*,int)),
75 this, SLOT(onReceiveBlock(const char*,int)), Qt::BlockingQueuedConnection);
76
77 connect( _emulation, SIGNAL(sendData(const char*,int))
78 ,this,SLOT(sendData(const char*,int)));
79
80 //connect( _emulation,SIGNAL(lockPtyRequest(bool)),_shellProcess,SLOT(lockPty(bool)) );
81 //connect( _emulation,SIGNAL(useUtf8Request(bool)),_shellProcess,SLOT(setUtf8Mode(bool)) );
82
83
84 //connect( _shellProcess,SIGNAL(done(int)), this, SLOT(done(int)) );
85
86 //setup timer for monitoring session activity
87 _monitorTimer = new QTimer(this);
88 _monitorTimer->setSingleShot(true);
89 connect(_monitorTimer, SIGNAL(timeout()), this, SLOT(monitorTimerDone()));
90 }
91
92 void TerminalModel::setDarkBackground(bool darkBackground)
93 {
94 _hasDarkBackground = darkBackground;
95 }
96 bool TerminalModel::hasDarkBackground() const
97 {
98 return _hasDarkBackground;
99 }
100
101 void TerminalModel::setCodec(QTextCodec* codec)
102 {
103 emulation()->setCodec(codec);
104 }
105
106 QList<TerminalView*> TerminalModel::views() const
107 {
108 return _views;
109 }
110
111 void TerminalModel::addView(TerminalView* widget)
112 {
113 Q_ASSERT( !_views.contains(widget) );
114
115 _views.append(widget);
116
117 if ( _emulation != 0 )
118 {
119 // connect emulation - view signals and slots
120 connect( widget , SIGNAL(keyPressedSignal(QKeyEvent*)) , _emulation ,
121 SLOT(sendKeyEvent(QKeyEvent*)) );
122 connect( widget , SIGNAL(mouseSignal(int,int,int,int)) , _emulation ,
123 SLOT(sendMouseEvent(int,int,int,int)) );
124 connect( widget , SIGNAL(sendStringToEmu(const char*)) , _emulation ,
125 SLOT(sendString(const char*)) );
126
127 // allow emulation to notify view when the foreground process
128 // indicates whether or not it is interested in mouse signals
129 connect( _emulation , SIGNAL(programUsesMouseChanged(bool)) , widget ,
130 SLOT(setUsesMouse(bool)) );
131
132 widget->setUsesMouse( _emulation->programUsesMouse() );
133
134 widget->setScreenWindow(_emulation->createWindow());
135 }
136
137 //connect view signals and slots
138 QObject::connect( widget ,SIGNAL(changedContentSizeSignal(int,int)),this,
139 SLOT(onViewSizeChange(int,int)));
140
141 QObject::connect( widget ,SIGNAL(destroyed(QObject*)) , this ,
142 SLOT(viewDestroyed(QObject*)) );
143 //slot for close
144 //QObject::connect(this, SIGNAL(finished()), widget, SLOT(close()));
145 }
146
147 void TerminalModel::viewDestroyed(QObject* view)
148 {
149 TerminalView* display = (TerminalView*)view;
150
151 Q_ASSERT( _views.contains(display) );
152
153 removeView(display);
154 }
155
156 void TerminalModel::sendData(const char *buf, int len)
157 {
158 ssize_t bytesWritten = ::write(_kpty->masterFd(), buf, len);
159 (void)bytesWritten;
160 }
161
162 void TerminalModel::removeView(TerminalView* widget)
163 {
164 _views.removeAll(widget);
165
166 disconnect(widget,0,this,0);
167
168 if ( _emulation != 0 )
169 {
170 // disconnect
171 // - key presses signals from widget
172 // - mouse activity signals from widget
173 // - string sending signals from widget
174 //
175 // ... and any other signals connected in addView()
176 disconnect( widget, 0, _emulation, 0);
177
178 // disconnect state change signals emitted by emulation
179 disconnect( _emulation , 0 , widget , 0);
180 }
181
182 // close the session automatically when the last view is removed
183 if ( _views.count() == 0 )
184 {
185 close();
186 }
187 }
188
189 void TerminalModel::run()
190 {
191 emit started();
192 }
193
194 void TerminalModel::monitorTimerDone()
195 {
196 //FIXME: The idea here is that the notification popup will appear to tell the user than output from
197 //the terminal has stopped and the popup will disappear when the user activates the session.
198 //
199 //This breaks with the addition of multiple views of a session. The popup should disappear
200 //when any of the views of the session becomes active
201
202
203 //FIXME: Make message text for this notification and the activity notification more descriptive.
204 if (_monitorSilence) {
205 // KNotification::event("Silence", ("Silence in session '%1'", _nameTitle), QPixmap(),
206 // QApplication::activeWindow(),
207 // KNotification::CloseWhenWidgetActivated);
208 emit stateChanged(NOTIFYSILENCE);
209 }
210 else
211 {
212 emit stateChanged(NOTIFYNORMAL);
213 }
214
215 _notifiedActivity=false;
216 }
217
218 void TerminalModel::activityStateSet(int state)
219 {
220 if (state==NOTIFYBELL)
221 {
222 emit bellRequest("");
223 }
224 else if (state==NOTIFYACTIVITY)
225 {
226 if (_monitorSilence) {
227 _monitorTimer->start(_silenceSeconds*1000);
228 }
229
230 if ( _monitorActivity ) {
231 //FIXME: See comments in Session::monitorTimerDone()
232 if (!_notifiedActivity) {
233 // KNotification::event("Activity", ("Activity in session '%1'", _nameTitle), QPixmap(),
234 // QApplication::activeWindow(),
235 // KNotification::CloseWhenWidgetActivated);
236 _notifiedActivity=true;
237 }
238 }
239 }
240
241 if ( state==NOTIFYACTIVITY && !_monitorActivity )
242 state = NOTIFYNORMAL;
243 if ( state==NOTIFYSILENCE && !_monitorSilence )
244 state = NOTIFYNORMAL;
245
246 emit stateChanged(state);
247 }
248
249 void TerminalModel::onViewSizeChange(int /*height*/, int /*width*/)
250 {
251 updateTerminalSize();
252 }
253 void TerminalModel::onEmulationSizeChange(int lines , int columns)
254 {
255 setSize( QSize(lines,columns) );
256 }
257
258 void TerminalModel::updateTerminalSize()
259 {
260 QListIterator<TerminalView*> viewIter(_views);
261
262 int minLines = -1;
263 int minColumns = -1;
264
265 // minimum number of lines and columns that views require for
266 // their size to be taken into consideration ( to avoid problems
267 // with new view widgets which haven't yet been set to their correct size )
268 const int VIEW_LINES_THRESHOLD = 2;
269 const int VIEW_COLUMNS_THRESHOLD = 2;
270
271 //select largest number of lines and columns that will fit in all visible views
272 while ( viewIter.hasNext() )
273 {
274 TerminalView* view = viewIter.next();
275 if ( view->isHidden() == false &&
276 view->lines() >= VIEW_LINES_THRESHOLD &&
277 view->columns() >= VIEW_COLUMNS_THRESHOLD )
278 {
279 minLines = (minLines == -1) ? view->lines() : qMin( minLines , view->lines() );
280 minColumns = (minColumns == -1) ? view->columns() : qMin( minColumns , view->columns() );
281 }
282 }
283
284 // backend emulation must have a _terminal of at least 1 column x 1 line in size
285 if ( minLines > 0 && minColumns > 0 )
286 {
287 _emulation->setImageSize( minLines , minColumns );
288 //_shellProcess->setWindowSize( minLines , minColumns );
289 }
290 }
291
292 void TerminalModel::refresh()
293 {
294 }
295
296 void TerminalModel::close()
297 {
298 _autoClose = true;
299 _wantedClose = true;
300 }
301
302 void TerminalModel::sendText(const QString &text) const
303 {
304 _emulation->sendText(text);
305 }
306
307 TerminalModel::~TerminalModel()
308 {
309 delete _emulation;
310 }
311
312 void TerminalModel::setProfileKey(const QString& key)
313 {
314 _profileKey = key;
315 emit profileChanged(key);
316 }
317 QString TerminalModel::profileKey() const { return _profileKey; }
318
319 void TerminalModel::done(int)
320 {
321 emit finished();
322 }
323
324 Emulation* TerminalModel::emulation() const
325 {
326 return _emulation;
327 }
328
329 QString TerminalModel::keyBindings() const
330 {
331 return _emulation->keyBindings();
332 }
333
334 void TerminalModel::setKeyBindings(const QString &id)
335 {
336 _emulation->setKeyBindings(id);
337 }
338
339 void TerminalModel::setHistoryType(const HistoryType &hType)
340 {
341 _emulation->setHistory(hType);
342 }
343
344 const HistoryType& TerminalModel::historyType() const
345 {
346 return _emulation->history();
347 }
348
349 void TerminalModel::clearHistory()
350 {
351 _emulation->clearHistory();
352 }
353
354 // unused currently
355 bool TerminalModel::isMonitorActivity() const { return _monitorActivity; }
356 // unused currently
357 bool TerminalModel::isMonitorSilence() const { return _monitorSilence; }
358
359 void TerminalModel::setMonitorActivity(bool _monitor)
360 {
361 _monitorActivity=_monitor;
362 _notifiedActivity=false;
363
364 activityStateSet(NOTIFYNORMAL);
365 }
366
367 void TerminalModel::setMonitorSilence(bool _monitor)
368 {
369 if (_monitorSilence==_monitor)
370 return;
371
372 _monitorSilence=_monitor;
373 if (_monitorSilence)
374 {
375 _monitorTimer->start(_silenceSeconds*1000);
376 }
377 else
378 _monitorTimer->stop();
379
380 activityStateSet(NOTIFYNORMAL);
381 }
382
383 void TerminalModel::setMonitorSilenceSeconds(int seconds)
384 {
385 _silenceSeconds=seconds;
386 if (_monitorSilence) {
387 _monitorTimer->start(_silenceSeconds*1000);
388 }
389 }
390
391 void TerminalModel::setAddToUtmp(bool set)
392 {
393 _addToUtmp = set;
394 }
395
396 void TerminalModel::onReceiveBlock(const char* buf, int len )
397 {
398 _emulation->receiveData( buf, len );
399 emit receivedData( QString::fromLatin1( buf, len ) );
400 }
401
402 QSize TerminalModel::size()
403 {
404 return _emulation->imageSize();
405 }
406
407 void TerminalModel::setSize(const QSize& size)
408 {
409 if ((size.width() <= 1) || (size.height() <= 1))
410 return;
411
412 emit resizeRequest(size);
413 }