GNU Octave  3.8.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
TerminalModel.cpp
Go to the documentation of this file.
1 /*
2  This file is part of Konsole
3 
4  Copyright (C) 2006-2007 by Robert Knight <[email protected]>
5  Copyright (C) 1997,1998 by Lars Doelle <[email protected]>
6 
7  Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
8  Copyright (C) 2012-2013 Jacob Dawid <[email protected]>
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/TerminalModel.h"
28 
29 // Standard
30 #include <assert.h>
31 #include <stdlib.h>
32 
33 // Qt
34 #include <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 "unix/TerminalView.h"
43 #include "unix/Vt102Emulation.h"
44 
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 }
97 {
98  return _hasDarkBackground;
99 }
100 
101 void TerminalModel::setCodec(QTextCodec* codec)
102 {
103  emulation()->setCodec(codec);
104 }
105 
107 {
108  return _views;
109 }
110 
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 
133 
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 
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 
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 
190 {
191  emit started();
192 }
193 
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);
209  }
210  else
211  {
213  }
214 
215  _notifiedActivity=false;
216 }
217 
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 {
252 }
253 void TerminalModel::onEmulationSizeChange(int lines , int columns)
254 {
255  setSize( QSize(lines,columns) );
256 }
257 
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  _kpty->setWinSize (minLines, minColumns);
289  //_shellProcess->setWindowSize( minLines , minColumns );
290  }
291 }
292 
294 {
295 }
296 
298 {
299  _autoClose = true;
300  _wantedClose = true;
301 }
302 
303 void TerminalModel::sendText(const QString &text) const
304 {
305  _emulation->sendText(text);
306 }
307 
309 {
310  delete _emulation;
311 }
312 
313 void TerminalModel::setProfileKey(const QString& key)
314 {
315  _profileKey = key;
316  emit profileChanged(key);
317 }
318 QString TerminalModel::profileKey() const { return _profileKey; }
319 
321 {
322  emit finished();
323 }
324 
326 {
327  return _emulation;
328 }
329 
330 QString TerminalModel::keyBindings() const
331 {
332  return _emulation->keyBindings();
333 }
334 
335 void TerminalModel::setKeyBindings(const QString &id)
336 {
338 }
339 
341 {
342  _emulation->setHistory(hType);
343 }
344 
346 {
347  return _emulation->history();
348 }
349 
351 {
353 }
354 
355 // unused currently
357 // unused currently
359 
361 {
362  _monitorActivity=_monitor;
363  _notifiedActivity=false;
364 
366 }
367 
369 {
370  if (_monitorSilence==_monitor)
371  return;
372 
373  _monitorSilence=_monitor;
374  if (_monitorSilence)
375  {
376  _monitorTimer->start(_silenceSeconds*1000);
377  }
378  else
379  _monitorTimer->stop();
380 
382 }
383 
385 {
386  _silenceSeconds=seconds;
387  if (_monitorSilence) {
388  _monitorTimer->start(_silenceSeconds*1000);
389  }
390 }
391 
393 {
394  _addToUtmp = set;
395 }
396 
397 void TerminalModel::onReceiveBlock(const char* buf, int len )
398 {
399  _emulation->receiveData( buf, len );
400  emit receivedData( QString::fromLatin1( buf, len ) );
401 }
402 
403 QSize TerminalModel::size()
404 {
405  return _emulation->imageSize();
406 }
407 
408 void TerminalModel::setSize(const QSize& size)
409 {
410  if ((size.width() <= 1) || (size.height() <= 1))
411  return;
412 
413  emit resizeRequest(size);
414 }