source: ogBrowser-Git/qtermwidget/src/Session.cpp @ 987869c

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