~lubuntu-dev/juffed/trunk

« back to all changes in this revision

Viewing changes to plugins/terminal/qtermwidget/lib/Session.cpp

  • Committer: Mikhail Murzin
  • Date: 2012-01-31 01:33:22 UTC
  • Revision ID: git-v1:28dda15acf875c1565ffd527d8d4e8daa88ac487
Added plugins

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
 
9
    This program is free software; you can redistribute it and/or modify
 
10
    it under the terms of the GNU General Public License as published by
 
11
    the Free Software Foundation; either version 2 of the License, or
 
12
    (at your option) any later version.
 
13
 
 
14
    This program is distributed in the hope that it will be useful,
 
15
    but WITHOUT ANY WARRANTY; without even the implied warranty of
 
16
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
17
    GNU General Public License for more details.
 
18
 
 
19
    You should have received a copy of the GNU General Public License
 
20
    along with this program; if not, write to the Free Software
 
21
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 
22
    02110-1301  USA.
 
23
*/
 
24
 
 
25
// Own
 
26
#include "Session.h"
 
27
 
 
28
// Standard
 
29
#include <assert.h>
 
30
#include <stdlib.h>
 
31
 
 
32
// Qt
 
33
#include <QtGui/QApplication>
 
34
#include <QtCore/QByteRef>
 
35
#include <QtCore/QDir>
 
36
#include <QtCore/QFile>
 
37
#include <QtCore/QRegExp>
 
38
#include <QtCore/QStringList>
 
39
#include <QtCore>
 
40
 
 
41
#include "Pty.h"
 
42
#include "TerminalDisplay.h"
 
43
#include "ShellCommand.h"
 
44
#include "Vt102Emulation.h"
 
45
 
 
46
using namespace Konsole;
 
47
 
 
48
int Session::lastSessionId = 0;
 
49
 
 
50
Session::Session() :
 
51
    _shellProcess(0)
 
52
   , _emulation(0)
 
53
   , _monitorActivity(false)
 
54
   , _monitorSilence(false)
 
55
   , _notifiedActivity(false)
 
56
   , _autoClose(true)
 
57
   , _wantedClose(false)
 
58
   , _silenceSeconds(10)
 
59
   , _addToUtmp(false)  // disabled by default because of a bug encountered on certain systems
 
60
                        // which caused Konsole to hang when closing a tab and then opening a new
 
61
                        // one.  A 'QProcess destroyed while still running' warning was being
 
62
                        // printed to the terminal.  Likely a problem in KPty::logout() 
 
63
                        // or KPty::login() which uses a QProcess to start /usr/bin/utempter 
 
64
   , _flowControl(true)
 
65
   , _fullScripting(false)
 
66
   , _sessionId(0)
 
67
//   , _zmodemBusy(false)
 
68
//   , _zmodemProc(0)
 
69
//   , _zmodemProgress(0)
 
70
   , _hasDarkBackground(false)
 
71
{
 
72
    //prepare DBus communication
 
73
//    new SessionAdaptor(this);
 
74
    _sessionId = ++lastSessionId;
 
75
//    QDBusConnection::sessionBus().registerObject(QLatin1String("/Sessions/")+QString::number(_sessionId), this);
 
76
 
 
77
    //create teletype for I/O with shell process
 
78
    _shellProcess = new Pty();
 
79
 
 
80
    //create emulation backend
 
81
    _emulation = new Vt102Emulation();
 
82
 
 
83
    connect( _emulation, SIGNAL( titleChanged( int, const QString & ) ),
 
84
           this, SLOT( setUserTitle( int, const QString & ) ) );
 
85
    connect( _emulation, SIGNAL( stateSet(int) ),
 
86
           this, SLOT( activityStateSet(int) ) );
 
87
//    connect( _emulation, SIGNAL( zmodemDetected() ), this ,
 
88
//            SLOT( fireZModemDetected() ) );
 
89
    connect( _emulation, SIGNAL( changeTabTextColorRequest( int ) ),
 
90
           this, SIGNAL( changeTabTextColorRequest( int ) ) );
 
91
    connect( _emulation, SIGNAL(profileChangeCommandReceived(const QString&)),
 
92
           this, SIGNAL( profileChangeCommandReceived(const QString&)) );
 
93
    // TODO
 
94
    // connect( _emulation,SIGNAL(imageSizeChanged(int,int)) , this ,
 
95
    //        SLOT(onEmulationSizeChange(int,int)) );
 
96
 
 
97
    //connect teletype to emulation backend
 
98
    _shellProcess->setUtf8Mode(_emulation->utf8());
 
99
 
 
100
    connect( _shellProcess,SIGNAL(receivedData(const char*,int)),this,
 
101
            SLOT(onReceiveBlock(const char*,int)) );
 
102
    connect( _emulation,SIGNAL(sendData(const char*,int)),_shellProcess,
 
103
            SLOT(sendData(const char*,int)) );
 
104
    connect( _emulation,SIGNAL(lockPtyRequest(bool)),_shellProcess,SLOT(lockPty(bool)) );
 
105
    connect( _emulation,SIGNAL(useUtf8Request(bool)),_shellProcess,SLOT(setUtf8Mode(bool)) );
 
106
 
 
107
 
 
108
    connect( _shellProcess,SIGNAL(done(int)), this, SLOT(done(int)) );
 
109
 
 
110
    //setup timer for monitoring session activity
 
111
    _monitorTimer = new QTimer(this);
 
112
    _monitorTimer->setSingleShot(true);
 
113
    connect(_monitorTimer, SIGNAL(timeout()), this, SLOT(monitorTimerDone()));
 
114
}
 
115
 
 
116
WId Session::windowId() const
 
117
{
 
118
    // Returns a window ID for this session which is used
 
119
    // to set the WINDOWID environment variable in the shell
 
120
    // process.
 
121
    //
 
122
    // Sessions can have multiple views or no views, which means
 
123
    // that a single ID is not always going to be accurate.
 
124
    //
 
125
    // If there are no views, the window ID is just 0.  If
 
126
    // there are multiple views, then the window ID for the
 
127
    // top-level window which contains the first view is
 
128
    // returned
 
129
 
 
130
    if ( _views.count() == 0 )
 
131
       return 0;
 
132
    else
 
133
    {
 
134
        QWidget* window = _views.first();
 
135
 
 
136
        Q_ASSERT( window );
 
137
 
 
138
        while ( window->parentWidget() != 0 )
 
139
            window = window->parentWidget();
 
140
 
 
141
        return window->winId();
 
142
    }
 
143
}
 
144
 
 
145
void Session::setDarkBackground(bool darkBackground)
 
146
{
 
147
    _hasDarkBackground = darkBackground;
 
148
}
 
149
bool Session::hasDarkBackground() const
 
150
{
 
151
    return _hasDarkBackground;
 
152
}
 
153
bool Session::isRunning() const
 
154
{
 
155
    return _shellProcess->isRunning();
 
156
}
 
157
 
 
158
void Session::setCodec(QTextCodec* codec)
 
159
{
 
160
    emulation()->setCodec(codec);
 
161
}
 
162
 
 
163
void Session::setProgram(const QString& program)
 
164
{
 
165
    _program = ShellCommand::expand(program);
 
166
}
 
167
void Session::setInitialWorkingDirectory(const QString& dir)
 
168
{
 
169
    _initialWorkingDir = ShellCommand::expand(dir);
 
170
}
 
171
void Session::setArguments(const QStringList& arguments)
 
172
{
 
173
    _arguments = ShellCommand::expand(arguments);
 
174
}
 
175
 
 
176
QList<TerminalDisplay*> Session::views() const
 
177
{
 
178
    return _views;
 
179
}
 
180
 
 
181
void Session::addView(TerminalDisplay* widget)
 
182
{
 
183
     Q_ASSERT( !_views.contains(widget) );
 
184
 
 
185
    _views.append(widget);
 
186
 
 
187
    if ( _emulation != 0 )
 
188
    {
 
189
        // connect emulation - view signals and slots
 
190
        connect( widget , SIGNAL(keyPressedSignal(QKeyEvent*)) , _emulation ,
 
191
               SLOT(sendKeyEvent(QKeyEvent*)) );
 
192
        connect( widget , SIGNAL(mouseSignal(int,int,int,int)) , _emulation ,
 
193
               SLOT(sendMouseEvent(int,int,int,int)) );
 
194
        connect( widget , SIGNAL(sendStringToEmu(const char*)) , _emulation ,
 
195
               SLOT(sendString(const char*)) );
 
196
 
 
197
        // allow emulation to notify view when the foreground process
 
198
        // indicates whether or not it is interested in mouse signals
 
199
        connect( _emulation , SIGNAL(programUsesMouseChanged(bool)) , widget ,
 
200
               SLOT(setUsesMouse(bool)) );
 
201
 
 
202
        widget->setUsesMouse( _emulation->programUsesMouse() );
 
203
 
 
204
        widget->setScreenWindow(_emulation->createWindow());
 
205
    }
 
206
 
 
207
    //connect view signals and slots
 
208
    QObject::connect( widget ,SIGNAL(changedContentSizeSignal(int,int)),this,
 
209
                    SLOT(onViewSizeChange(int,int)));
 
210
 
 
211
    QObject::connect( widget ,SIGNAL(destroyed(QObject*)) , this ,
 
212
                    SLOT(viewDestroyed(QObject*)) );
 
213
//slot for close
 
214
    QObject::connect(this, SIGNAL(finished()), widget, SLOT(close()));              
 
215
    
 
216
}
 
217
 
 
218
void Session::viewDestroyed(QObject* view)
 
219
{
 
220
    TerminalDisplay* display = (TerminalDisplay*)view;
 
221
 
 
222
    Q_ASSERT( _views.contains(display) );
 
223
 
 
224
    removeView(display);
 
225
}
 
226
 
 
227
void Session::removeView(TerminalDisplay* widget)
 
228
{
 
229
    _views.removeAll(widget);
 
230
 
 
231
        disconnect(widget,0,this,0);
 
232
 
 
233
    if ( _emulation != 0 )
 
234
    {
 
235
        // disconnect
 
236
        //  - key presses signals from widget
 
237
        //  - mouse activity signals from widget
 
238
        //  - string sending signals from widget
 
239
        //
 
240
        //  ... and any other signals connected in addView()
 
241
        disconnect( widget, 0, _emulation, 0);
 
242
 
 
243
        // disconnect state change signals emitted by emulation
 
244
        disconnect( _emulation , 0 , widget , 0);
 
245
    }
 
246
 
 
247
        // close the session automatically when the last view is removed
 
248
        if ( _views.count() == 0 )
 
249
        {
 
250
                close();
 
251
        }
 
252
}
 
253
 
 
254
void Session::run()
 
255
{
 
256
  //check that everything is in place to run the session
 
257
  if (_program.isEmpty())
 
258
      qDebug() << "Session::run() - program to run not set.";
 
259
  if (_arguments.isEmpty())
 
260
      qDebug() << "Session::run() - no command line arguments specified.";
 
261
 
 
262
  // Upon a KPty error, there is no description on what that error was...
 
263
  // Check to see if the given program is executable.
 
264
  QString exec = QFile::encodeName(_program);
 
265
 
 
266
  // if 'exec' is not specified, fall back to default shell.  if that 
 
267
  // is not set then fall back to /bin/sh
 
268
  if ( exec.isEmpty() )
 
269
      exec = getenv("SHELL");
 
270
  if ( exec.isEmpty() )
 
271
          exec = "/bin/sh";
 
272
 
 
273
  // if no arguments are specified, fall back to shell
 
274
  QStringList arguments =  _arguments.join(QChar(' ')).isEmpty() ?
 
275
                                    QStringList() << exec : _arguments;
 
276
  QString pexec = exec;
 
277
 
 
278
  if ( pexec.isEmpty() ) {
 
279
    qDebug()<<"can not execute "<<exec<<endl;
 
280
    QTimer::singleShot(1, this, SIGNAL(finished()));
 
281
    return;
 
282
  }
 
283
 
 
284
//  QString cwd_save = QDir::currentPath();
 
285
  QString cwd = QDir::currentPath();
 
286
  if (!_initialWorkingDir.isEmpty())
 
287
    _shellProcess->setWorkingDirectory(_initialWorkingDir);
 
288
  else
 
289
    _shellProcess->setWorkingDirectory(cwd);
 
290
//    _shellProcess->setWorkingDirectory(QDir::homePath());
 
291
 
 
292
  _shellProcess->setXonXoff(_flowControl);
 
293
  _shellProcess->setErase(_emulation->getErase());
 
294
 
 
295
  // this is not strictly accurate use of the COLORFGBG variable.  This does not
 
296
  // tell the terminal exactly which colors are being used, but instead approximates
 
297
  // the color scheme as "black on white" or "white on black" depending on whether
 
298
  // the background color is deemed dark or not
 
299
  QString backgroundColorHint = _hasDarkBackground ? "COLORFGBG=15;0" : "COLORFGBG=0;15";
 
300
 
 
301
  int result = _shellProcess->start(QFile::encodeName(_program),
 
302
                                  arguments,
 
303
                                  _environment << backgroundColorHint,
 
304
                                  windowId(),
 
305
                                  _addToUtmp);
 
306
 
 
307
  if (result < 0)
 
308
  {
 
309
    return;
 
310
  }
 
311
 
 
312
  _shellProcess->setWriteable(false);  // We are reachable via kwrited.
 
313
 
 
314
  emit started();
 
315
}
 
316
 
 
317
void Session::setUserTitle( int what, const QString &caption )
 
318
{
 
319
    //set to true if anything is actually changed (eg. old _nameTitle != new _nameTitle )
 
320
        bool modified = false;
 
321
 
 
322
    // (btw: what=0 changes _userTitle and icon, what=1 only icon, what=2 only _nameTitle
 
323
    if ((what == 0) || (what == 2)) 
 
324
    {
 
325
        if ( _userTitle != caption ) {
 
326
                        _userTitle = caption;
 
327
                        modified = true;
 
328
                }
 
329
    }
 
330
 
 
331
    if ((what == 0) || (what == 1))
 
332
        {
 
333
                if ( _iconText != caption ) {
 
334
                _iconText = caption;
 
335
                        modified = true;
 
336
                }
 
337
        }
 
338
 
 
339
    if (what == 11) 
 
340
    {
 
341
      QString colorString = caption.section(';',0,0);
 
342
      qDebug() << __FILE__ << __LINE__ << ": setting background colour to " << colorString;
 
343
      QColor backColor = QColor(colorString);
 
344
      if (backColor.isValid()){// change color via \033]11;Color\007
 
345
          if (backColor != _modifiedBackground)
 
346
          {
 
347
              _modifiedBackground = backColor;
 
348
 
 
349
              // bail out here until the code to connect the terminal display
 
350
              // to the changeBackgroundColor() signal has been written
 
351
              // and tested - just so we don't forget to do this.
 
352
              Q_ASSERT( 0 );
 
353
 
 
354
              emit changeBackgroundColorRequest(backColor);
 
355
          }
 
356
      }
 
357
    }
 
358
 
 
359
        if (what == 30) 
 
360
    {
 
361
                if ( _nameTitle != caption ) {
 
362
                setTitle(Session::NameRole,caption);
 
363
                        return;
 
364
                }
 
365
        }
 
366
 
 
367
    if (what == 31) 
 
368
    {
 
369
       QString cwd=caption;
 
370
       cwd=cwd.replace( QRegExp("^~"), QDir::homePath() );
 
371
       emit openUrlRequest(cwd);
 
372
        }
 
373
 
 
374
    // change icon via \033]32;Icon\007
 
375
    if (what == 32) 
 
376
    { 
 
377
        if ( _iconName != caption ) {
 
378
                        _iconName = caption;
 
379
 
 
380
                        modified = true;
 
381
                }
 
382
    }
 
383
 
 
384
    if (what == 50) 
 
385
    {
 
386
        emit profileChangeCommandReceived(caption);
 
387
        return;
 
388
    }
 
389
 
 
390
        if ( modified )
 
391
        emit titleChanged();
 
392
}
 
393
 
 
394
QString Session::userTitle() const
 
395
{
 
396
    return _userTitle;
 
397
}
 
398
void Session::setTabTitleFormat(TabTitleContext context , const QString& format)
 
399
{
 
400
    if ( context == LocalTabTitle )
 
401
        _localTabTitleFormat = format;
 
402
    else if ( context == RemoteTabTitle )
 
403
        _remoteTabTitleFormat = format;
 
404
}
 
405
QString Session::tabTitleFormat(TabTitleContext context) const
 
406
{
 
407
    if ( context == LocalTabTitle )
 
408
        return _localTabTitleFormat;
 
409
    else if ( context == RemoteTabTitle )
 
410
        return _remoteTabTitleFormat;
 
411
 
 
412
    return QString();
 
413
}
 
414
 
 
415
void Session::monitorTimerDone()
 
416
{
 
417
  //FIXME: The idea here is that the notification popup will appear to tell the user than output from
 
418
  //the terminal has stopped and the popup will disappear when the user activates the session.
 
419
  //
 
420
  //This breaks with the addition of multiple views of a session.  The popup should disappear
 
421
  //when any of the views of the session becomes active
 
422
  
 
423
 
 
424
  //FIXME: Make message text for this notification and the activity notification more descriptive.      
 
425
  if (_monitorSilence) {
 
426
//    KNotification::event("Silence", ("Silence in session '%1'", _nameTitle), QPixmap(),
 
427
//                    QApplication::activeWindow(),
 
428
//                    KNotification::CloseWhenWidgetActivated);
 
429
    emit stateChanged(NOTIFYSILENCE);
 
430
  }
 
431
  else
 
432
  {
 
433
    emit stateChanged(NOTIFYNORMAL);
 
434
  }
 
435
 
 
436
  _notifiedActivity=false;
 
437
}
 
438
 
 
439
void Session::activityStateSet(int state)
 
440
{
 
441
  if (state==NOTIFYBELL)
 
442
  {
 
443
      QString s; s.sprintf("Bell in session '%s'",_nameTitle.toAscii().data());
 
444
      
 
445
      emit bellRequest( s );
 
446
  }
 
447
  else if (state==NOTIFYACTIVITY)
 
448
  {
 
449
    if (_monitorSilence) {
 
450
      _monitorTimer->start(_silenceSeconds*1000);
 
451
    }
 
452
 
 
453
    if ( _monitorActivity ) {
 
454
      //FIXME:  See comments in Session::monitorTimerDone()
 
455
      if (!_notifiedActivity) {
 
456
//        KNotification::event("Activity", ("Activity in session '%1'", _nameTitle), QPixmap(),
 
457
//                        QApplication::activeWindow(),
 
458
//        KNotification::CloseWhenWidgetActivated);
 
459
        _notifiedActivity=true;
 
460
      }
 
461
    }
 
462
  }
 
463
 
 
464
  if ( state==NOTIFYACTIVITY && !_monitorActivity )
 
465
          state = NOTIFYNORMAL;
 
466
  if ( state==NOTIFYSILENCE && !_monitorSilence )
 
467
          state = NOTIFYNORMAL;
 
468
 
 
469
  emit stateChanged(state);
 
470
}
 
471
 
 
472
void Session::onViewSizeChange(int /*height*/, int /*width*/)
 
473
{
 
474
  updateTerminalSize();
 
475
}
 
476
void Session::onEmulationSizeChange(int lines , int columns)
 
477
{
 
478
  setSize( QSize(lines,columns) );
 
479
}
 
480
 
 
481
void Session::updateTerminalSize()
 
482
{
 
483
    QListIterator<TerminalDisplay*> viewIter(_views);
 
484
 
 
485
    int minLines = -1;
 
486
    int minColumns = -1;
 
487
 
 
488
    // minimum number of lines and columns that views require for
 
489
    // their size to be taken into consideration ( to avoid problems
 
490
    // with new view widgets which haven't yet been set to their correct size )
 
491
    const int VIEW_LINES_THRESHOLD = 2;
 
492
    const int VIEW_COLUMNS_THRESHOLD = 2;
 
493
 
 
494
    //select largest number of lines and columns that will fit in all visible views
 
495
    while ( viewIter.hasNext() )
 
496
    {
 
497
        TerminalDisplay* view = viewIter.next();
 
498
        if ( view->isHidden() == false &&
 
499
             view->lines() >= VIEW_LINES_THRESHOLD &&
 
500
             view->columns() >= VIEW_COLUMNS_THRESHOLD )
 
501
        {
 
502
            minLines = (minLines == -1) ? view->lines() : qMin( minLines , view->lines() );
 
503
            minColumns = (minColumns == -1) ? view->columns() : qMin( minColumns , view->columns() );
 
504
        }
 
505
    }
 
506
 
 
507
    // backend emulation must have a _terminal of at least 1 column x 1 line in size
 
508
    if ( minLines > 0 && minColumns > 0 )
 
509
    {
 
510
        _emulation->setImageSize( minLines , minColumns );
 
511
        _shellProcess->setWindowSize( minLines , minColumns );
 
512
    }
 
513
}
 
514
 
 
515
void Session::refresh()
 
516
{
 
517
    // attempt to get the shell process to redraw the display
 
518
    //
 
519
    // this requires the program running in the shell
 
520
    // to cooperate by sending an update in response to
 
521
    // a window size change
 
522
    //
 
523
    // the window size is changed twice, first made slightly larger and then
 
524
    // resized back to its normal size so that there is actually a change
 
525
    // in the window size (some shells do nothing if the
 
526
    // new and old sizes are the same)
 
527
    //
 
528
    // if there is a more 'correct' way to do this, please
 
529
    // send an email with method or patches to konsole-devel@kde.org
 
530
 
 
531
    const QSize existingSize = _shellProcess->windowSize();
 
532
    _shellProcess->setWindowSize(existingSize.height(),existingSize.width()+1);
 
533
    _shellProcess->setWindowSize(existingSize.height(),existingSize.width());
 
534
}
 
535
 
 
536
bool Session::sendSignal(int signal)
 
537
{
 
538
  return _shellProcess->kill(signal);
 
539
}
 
540
 
 
541
void Session::close()
 
542
{
 
543
  _autoClose = true;
 
544
  _wantedClose = true;
 
545
  if (!_shellProcess->isRunning() || !sendSignal(SIGHUP))
 
546
  {
 
547
     // Forced close.
 
548
     QTimer::singleShot(1, this, SIGNAL(finished()));
 
549
  }
 
550
}
 
551
 
 
552
void Session::sendText(const QString &text) const
 
553
{
 
554
  _emulation->sendText(text);
 
555
}
 
556
 
 
557
Session::~Session()
 
558
{
 
559
  delete _emulation;
 
560
  delete _shellProcess;
 
561
//  delete _zmodemProc;
 
562
}
 
563
 
 
564
void Session::setProfileKey(const QString& key)
 
565
{
 
566
    _profileKey = key;
 
567
    emit profileChanged(key);
 
568
}
 
569
QString Session::profileKey() const { return _profileKey; }
 
570
 
 
571
void Session::done(int exitStatus)
 
572
{
 
573
  if (!_autoClose)
 
574
  {
 
575
    _userTitle = ("<Finished>");
 
576
    emit titleChanged();
 
577
    return;
 
578
  }
 
579
  if (!_wantedClose && (exitStatus || _shellProcess->signalled()))
 
580
  {
 
581
    QString message;
 
582
 
 
583
    if (_shellProcess->normalExit())
 
584
      message.sprintf ("Session '%s' exited with status %d.", _nameTitle.toAscii().data(), exitStatus);
 
585
    else if (_shellProcess->signalled())
 
586
    {
 
587
      if (_shellProcess->coreDumped())
 
588
      {    
 
589
 
 
590
        message.sprintf("Session '%s' exited with signal %d and dumped core.", _nameTitle.toAscii().data(), _shellProcess->exitSignal());
 
591
      }
 
592
      else { 
 
593
        message.sprintf("Session '%s' exited with signal %d.", _nameTitle.toAscii().data(), _shellProcess->exitSignal());
 
594
      }
 
595
    }
 
596
    else
 
597
        message.sprintf ("Session '%s' exited unexpectedly.", _nameTitle.toAscii().data());
 
598
 
 
599
    //FIXME: See comments in Session::monitorTimerDone()
 
600
//    KNotification::event("Finished", message , QPixmap(),
 
601
//                         QApplication::activeWindow(),
 
602
//                         KNotification::CloseWhenWidgetActivated);
 
603
  }
 
604
  emit finished();
 
605
}
 
606
 
 
607
Emulation* Session::emulation() const
 
608
{
 
609
  return _emulation;
 
610
}
 
611
 
 
612
QString Session::keyBindings() const
 
613
{
 
614
  return _emulation->keyBindings();
 
615
}
 
616
 
 
617
QStringList Session::environment() const
 
618
{
 
619
  return _environment;
 
620
}
 
621
 
 
622
void Session::setEnvironment(const QStringList& environment)
 
623
{
 
624
    _environment = environment;
 
625
}
 
626
 
 
627
int Session::sessionId() const
 
628
{
 
629
  return _sessionId;
 
630
}
 
631
 
 
632
void Session::setKeyBindings(const QString &id)
 
633
{
 
634
  _emulation->setKeyBindings(id);
 
635
}
 
636
 
 
637
void Session::setTitle(TitleRole role , const QString& newTitle)
 
638
{
 
639
    if ( title(role) != newTitle )
 
640
    {
 
641
        if ( role == NameRole )
 
642
            _nameTitle = newTitle;
 
643
        else if ( role == DisplayedTitleRole )
 
644
            _displayTitle = newTitle;
 
645
 
 
646
        emit titleChanged();
 
647
    }
 
648
}
 
649
 
 
650
QString Session::title(TitleRole role) const
 
651
{
 
652
    if ( role == NameRole )
 
653
        return _nameTitle;
 
654
    else if ( role == DisplayedTitleRole )
 
655
        return _displayTitle;
 
656
    else
 
657
        return QString();
 
658
}
 
659
 
 
660
void Session::setIconName(const QString& iconName)
 
661
{
 
662
    if ( iconName != _iconName )
 
663
    {
 
664
        _iconName = iconName;
 
665
        emit titleChanged();
 
666
    }
 
667
}
 
668
 
 
669
void Session::setIconText(const QString& iconText)
 
670
{
 
671
  _iconText = iconText;
 
672
  //kDebug(1211)<<"Session setIconText " <<  _iconText;
 
673
}
 
674
 
 
675
QString Session::iconName() const
 
676
{
 
677
  return _iconName;
 
678
}
 
679
 
 
680
QString Session::iconText() const
 
681
{
 
682
  return _iconText;
 
683
}
 
684
 
 
685
void Session::setHistoryType(const HistoryType &hType)
 
686
{
 
687
  _emulation->setHistory(hType);
 
688
}
 
689
 
 
690
const HistoryType& Session::historyType() const
 
691
{
 
692
  return _emulation->history();
 
693
}
 
694
 
 
695
void Session::clearHistory()
 
696
{
 
697
    _emulation->clearHistory();
 
698
}
 
699
 
 
700
QStringList Session::arguments() const
 
701
{
 
702
  return _arguments;
 
703
}
 
704
 
 
705
QString Session::program() const
 
706
{
 
707
  return _program;
 
708
}
 
709
 
 
710
// unused currently
 
711
bool Session::isMonitorActivity() const { return _monitorActivity; }
 
712
// unused currently
 
713
bool Session::isMonitorSilence()  const { return _monitorSilence; }
 
714
 
 
715
void Session::setMonitorActivity(bool _monitor)
 
716
{
 
717
  _monitorActivity=_monitor;
 
718
  _notifiedActivity=false;
 
719
 
 
720
  activityStateSet(NOTIFYNORMAL);
 
721
}
 
722
 
 
723
void Session::setMonitorSilence(bool _monitor)
 
724
{
 
725
  if (_monitorSilence==_monitor)
 
726
    return;
 
727
 
 
728
  _monitorSilence=_monitor;
 
729
  if (_monitorSilence)
 
730
  {
 
731
    _monitorTimer->start(_silenceSeconds*1000);
 
732
  }
 
733
  else
 
734
    _monitorTimer->stop();
 
735
 
 
736
  activityStateSet(NOTIFYNORMAL);
 
737
}
 
738
 
 
739
void Session::setMonitorSilenceSeconds(int seconds)
 
740
{
 
741
  _silenceSeconds=seconds;
 
742
  if (_monitorSilence) {
 
743
    _monitorTimer->start(_silenceSeconds*1000);
 
744
  }
 
745
}
 
746
 
 
747
void Session::setAddToUtmp(bool set)
 
748
{
 
749
  _addToUtmp = set;
 
750
}
 
751
 
 
752
void Session::setFlowControlEnabled(bool enabled)
 
753
{
 
754
  if (_flowControl == enabled)
 
755
        return;
 
756
 
 
757
  _flowControl = enabled;
 
758
 
 
759
  if (_shellProcess)  
 
760
        _shellProcess->setXonXoff(_flowControl);
 
761
  
 
762
  emit flowControlEnabledChanged(enabled);
 
763
}
 
764
bool Session::flowControlEnabled() const
 
765
{
 
766
        return _flowControl;
 
767
}
 
768
//void Session::fireZModemDetected()
 
769
//{
 
770
//  if (!_zmodemBusy)
 
771
//  {
 
772
//    QTimer::singleShot(10, this, SIGNAL(zmodemDetected()));
 
773
//    _zmodemBusy = true;
 
774
//  }
 
775
//}
 
776
 
 
777
//void Session::cancelZModem()
 
778
//{
 
779
//  _shellProcess->sendData("\030\030\030\030", 4); // Abort
 
780
//  _zmodemBusy = false;
 
781
//}
 
782
 
 
783
//void Session::startZModem(const QString &zmodem, const QString &dir, const QStringList &list)
 
784
//{
 
785
//  _zmodemBusy = true;
 
786
//  _zmodemProc = new KProcess();
 
787
//  _zmodemProc->setOutputChannelMode( KProcess::SeparateChannels );
 
788
//
 
789
//  *_zmodemProc << zmodem << "-v" << list;
 
790
//
 
791
//  if (!dir.isEmpty())
 
792
//     _zmodemProc->setWorkingDirectory(dir);
 
793
//
 
794
//  _zmodemProc->start();
 
795
//
 
796
//  connect(_zmodemProc,SIGNAL (readyReadStandardOutput()),
 
797
//          this, SLOT(zmodemReadAndSendBlock()));
 
798
//  connect(_zmodemProc,SIGNAL (readyReadStandardError()),
 
799
//          this, SLOT(zmodemReadStatus()));
 
800
//  connect(_zmodemProc,SIGNAL (finished(int,QProcess::ExitStatus)),
 
801
//          this, SLOT(zmodemFinished()));
 
802
//
 
803
//  disconnect( _shellProcess,SIGNAL(block_in(const char*,int)), this, SLOT(onReceiveBlock(const char*,int)) );
 
804
//  connect( _shellProcess,SIGNAL(block_in(const char*,int)), this, SLOT(zmodemRcvBlock(const char*,int)) );
 
805
//
 
806
//  _zmodemProgress = new ZModemDialog(QApplication::activeWindow(), false,
 
807
//                                    i18n("ZModem Progress"));
 
808
//
 
809
//  connect(_zmodemProgress, SIGNAL(user1Clicked()),
 
810
//          this, SLOT(zmodemDone()));
 
811
//
 
812
//  _zmodemProgress->show();
 
813
//}
 
814
 
 
815
/*void Session::zmodemReadAndSendBlock()
 
816
{
 
817
  _zmodemProc->setReadChannel( QProcess::StandardOutput );
 
818
  QByteArray data = _zmodemProc->readAll();
 
819
 
 
820
  if ( data.count() == 0 )
 
821
      return;
 
822
 
 
823
  _shellProcess->sendData(data.constData(),data.count());
 
824
}
 
825
*/
 
826
/*
 
827
void Session::zmodemReadStatus()
 
828
{
 
829
  _zmodemProc->setReadChannel( QProcess::StandardError );
 
830
  QByteArray msg = _zmodemProc->readAll();
 
831
  while(!msg.isEmpty())
 
832
  {
 
833
     int i = msg.indexOf('\015');
 
834
     int j = msg.indexOf('\012');
 
835
     QByteArray txt;
 
836
     if ((i != -1) && ((j == -1) || (i < j)))
 
837
     {
 
838
       msg = msg.mid(i+1);
 
839
     }
 
840
     else if (j != -1)
 
841
     {
 
842
       txt = msg.left(j);
 
843
       msg = msg.mid(j+1);
 
844
     }
 
845
     else
 
846
     {
 
847
       txt = msg;
 
848
       msg.truncate(0);
 
849
     }
 
850
     if (!txt.isEmpty())
 
851
       _zmodemProgress->addProgressText(QString::fromLocal8Bit(txt));
 
852
  }
 
853
}
 
854
*/
 
855
/*
 
856
void Session::zmodemRcvBlock(const char *data, int len)
 
857
{
 
858
  QByteArray ba( data, len );
 
859
 
 
860
  _zmodemProc->write( ba );
 
861
}
 
862
*/
 
863
/*
 
864
void Session::zmodemFinished()
 
865
{
 
866
  if (_zmodemProc)
 
867
  {
 
868
    delete _zmodemProc;
 
869
    _zmodemProc = 0;
 
870
    _zmodemBusy = false;
 
871
 
 
872
    disconnect( _shellProcess,SIGNAL(block_in(const char*,int)), this ,SLOT(zmodemRcvBlock(const char*,int)) );
 
873
    connect( _shellProcess,SIGNAL(block_in(const char*,int)), this, SLOT(onReceiveBlock(const char*,int)) );
 
874
 
 
875
    _shellProcess->sendData("\030\030\030\030", 4); // Abort
 
876
    _shellProcess->sendData("\001\013\n", 3); // Try to get prompt back
 
877
    _zmodemProgress->transferDone();
 
878
  }
 
879
}
 
880
*/
 
881
void Session::onReceiveBlock( const char* buf, int len )
 
882
{
 
883
    _emulation->receiveData( buf, len );
 
884
    emit receivedData( QString::fromLatin1( buf, len ) );
 
885
}
 
886
 
 
887
QSize Session::size()
 
888
{
 
889
  return _emulation->imageSize();
 
890
}
 
891
 
 
892
void Session::setSize(const QSize& size)
 
893
{
 
894
  if ((size.width() <= 1) || (size.height() <= 1))
 
895
     return;
 
896
 
 
897
  emit resizeRequest(size);
 
898
}
 
899
int Session::foregroundProcessId() const
 
900
{
 
901
    return _shellProcess->foregroundProcessGroup();
 
902
}
 
903
int Session::processId() const
 
904
{
 
905
    return _shellProcess->pid();
 
906
}
 
907
 
 
908
SessionGroup::SessionGroup()
 
909
    : _masterMode(0)
 
910
{
 
911
}
 
912
SessionGroup::~SessionGroup()
 
913
{
 
914
    // disconnect all
 
915
    connectAll(false);
 
916
}
 
917
int SessionGroup::masterMode() const { return _masterMode; }
 
918
QList<Session*> SessionGroup::sessions() const { return _sessions.keys(); }
 
919
bool SessionGroup::masterStatus(Session* session) const { return _sessions[session]; }
 
920
 
 
921
void SessionGroup::addSession(Session* session)
 
922
{
 
923
    _sessions.insert(session,false);
 
924
 
 
925
    QListIterator<Session*> masterIter(masters());
 
926
 
 
927
    while ( masterIter.hasNext() )
 
928
        connectPair(masterIter.next(),session);
 
929
}
 
930
void SessionGroup::removeSession(Session* session)
 
931
{
 
932
    setMasterStatus(session,false);
 
933
 
 
934
    QListIterator<Session*> masterIter(masters());
 
935
 
 
936
    while ( masterIter.hasNext() )
 
937
        disconnectPair(masterIter.next(),session);
 
938
 
 
939
    _sessions.remove(session);
 
940
}
 
941
void SessionGroup::setMasterMode(int mode)
 
942
{
 
943
   _masterMode = mode;
 
944
 
 
945
   connectAll(false);
 
946
   connectAll(true);
 
947
}
 
948
QList<Session*> SessionGroup::masters() const
 
949
{
 
950
    return _sessions.keys(true);
 
951
}
 
952
void SessionGroup::connectAll(bool connect)
 
953
{
 
954
    QListIterator<Session*> masterIter(masters());
 
955
 
 
956
    while ( masterIter.hasNext() )
 
957
    {
 
958
        Session* master = masterIter.next();
 
959
 
 
960
        QListIterator<Session*> otherIter(_sessions.keys());
 
961
        while ( otherIter.hasNext() )
 
962
        {
 
963
            Session* other = otherIter.next();
 
964
 
 
965
            if ( other != master )
 
966
            {
 
967
                if ( connect )
 
968
                    connectPair(master,other);
 
969
                else
 
970
                    disconnectPair(master,other);
 
971
            }
 
972
        }
 
973
    }
 
974
}
 
975
void SessionGroup::setMasterStatus(Session* session, bool master) {
 
976
    bool wasMaster = _sessions[session];
 
977
    _sessions[session] = master;
 
978
 
 
979
    if ((!wasMaster && !master)
 
980
                || (wasMaster && master)) {
 
981
      return;
 
982
        }
 
983
 
 
984
    QListIterator<Session*> iter(_sessions.keys());
 
985
    while (iter.hasNext()) {
 
986
        Session* other = iter.next();
 
987
 
 
988
        if (other != session) {
 
989
                  if (master) {
 
990
                connectPair(session, other);
 
991
                  } else {
 
992
                disconnectPair(session, other);
 
993
                  }
 
994
        }
 
995
    }
 
996
}
 
997
 
 
998
void SessionGroup::connectPair(Session* master , Session* other)
 
999
{
 
1000
//    qDebug() << k_funcinfo;
 
1001
 
 
1002
    if ( _masterMode & CopyInputToAll )
 
1003
    {
 
1004
        qDebug() << "Connection session " << master->nameTitle() << "to" << other->nameTitle();
 
1005
 
 
1006
        connect( master->emulation() , SIGNAL(sendData(const char*,int)) , other->emulation() ,
 
1007
                 SLOT(sendString(const char*,int)) );
 
1008
    }
 
1009
}
 
1010
void SessionGroup::disconnectPair(Session* master , Session* other)
 
1011
{
 
1012
//    qDebug() << k_funcinfo;
 
1013
 
 
1014
    if ( _masterMode & CopyInputToAll )
 
1015
    {
 
1016
        qDebug() << "Disconnecting session " << master->nameTitle() << "from" << other->nameTitle();
 
1017
 
 
1018
        disconnect( master->emulation() , SIGNAL(sendData(const char*,int)) , other->emulation() ,
 
1019
                SLOT(sendString(const char*,int)) );
 
1020
    }
 
1021
}
 
1022
 
 
1023
//#include "moc_Session.cpp"