2
This file is part of Konsole
4
Copyright (C) 2006-2007 by Robert Knight <robertknight@gmail.com>
5
Copyright (C) 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
7
Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C) 2008
8
Rewritten for QT5/QML by Dmitry Zagnoyko <hiroshidi@gmail.com>, Copyright (C) 2013
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.
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.
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
34
#include <QGuiApplication>
35
#include <QtGui/QWindow>
37
#include <QtCore/QByteRef>
38
#include <QtCore/QDir>
39
#include <QtCore/QFile>
40
#include <QtCore/QRegExp>
41
#include <QtCore/QStringList>
42
#include <QtCore/QFile>
45
#include "Pty.h" // REUSE THIS
46
//#include "kptyprocess.h"
47
#include "TerminalDisplay.h"
48
#include "ShellCommand.h" // REUSE THIS
49
#include "Vt102Emulation.h" // REUSE THIS
52
int Session::lastSessionId = 0;
57
, _monitorActivity(false)
58
, _monitorSilence(false)
59
, _notifiedActivity(false)
63
, _addToUtmp(false) // disabled by default because of a bug encountered on certain systems
64
// which caused Konsole to hang when closing a tab and then opening a new
65
// one. A 'QProcess destroyed while still running' warning was being
66
// printed to the terminal. Likely a problem in KPty::logout()
67
// or KPty::login() which uses a QProcess to start /usr/bin/utempter
69
, _fullScripting(false)
71
// , _zmodemBusy(false)
73
// , _zmodemProgress(0)
74
, _hasDarkBackground(false)
76
//prepare DBus communication
77
// new SessionAdaptor(this);
78
_sessionId = ++lastSessionId;
79
// QDBusConnection::sessionBus().registerObject(QLatin1String("/Sessions/")+QString::number(_sessionId), this);
81
//create teletype for I/O with shell process
82
_shellProcess = new Pty();
84
//create emulation backend
85
_emulation = new Vt102Emulation();
87
connect( _emulation, SIGNAL( titleChanged( int, const QString & ) ),
88
this, SLOT( setUserTitle( int, const QString & ) ) );
89
connect( _emulation, SIGNAL( stateSet(int) ),
90
this, SLOT( activityStateSet(int) ) );
91
// connect( _emulation, SIGNAL( zmodemDetected() ), this ,
92
// SLOT( fireZModemDetected() ) );
93
connect( _emulation, SIGNAL( changeTabTextColorRequest( int ) ),
94
this, SIGNAL( changeTabTextColorRequest( int ) ) );
95
connect( _emulation, SIGNAL(profileChangeCommandReceived(const QString &)),
96
this, SIGNAL( profileChangeCommandReceived(const QString &)) );
98
// connect( _emulation,SIGNAL(imageSizeChanged(int,int)) , this ,
99
// SLOT(onEmulationSizeChange(int,int)) );
101
//connect teletype to emulation backend
102
_shellProcess->setUtf8Mode(_emulation->utf8());
104
connect( _shellProcess,SIGNAL(receivedData(const char *,int)),this,
105
SLOT(onReceiveBlock(const char *,int)) );
106
connect( _emulation,SIGNAL(sendData(const char *,int)),_shellProcess,
107
SLOT(sendData(const char *,int)) );
108
connect( _emulation,SIGNAL(lockPtyRequest(bool)),_shellProcess,SLOT(lockPty(bool)) );
109
connect( _emulation,SIGNAL(useUtf8Request(bool)),_shellProcess,SLOT(setUtf8Mode(bool)) );
111
connect( _shellProcess,SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(done(int)) );
112
// not in kprocess anymore connect( _shellProcess,SIGNAL(done(int)), this, SLOT(done(int)) );
114
//setup timer for monitoring session activity
115
_monitorTimer = new QTimer(this);
116
_monitorTimer->setSingleShot(true);
117
connect(_monitorTimer, SIGNAL(timeout()), this, SLOT(monitorTimerDone()));
120
WId Session::windowId() const
122
// Returns a window ID for this session which is used
123
// to set the WINDOWID environment variable in the shell
126
// Sessions can have multiple views or no views, which means
127
// that a single ID is not always going to be accurate.
129
// If there are no views, the window ID is just 0. If
130
// there are multiple views, then the window ID for the
131
// top-level window which contains the first view is
134
if ( _views.count() == 0 ) {
137
// QQuickItem * window = _views.first();
139
// Q_ASSERT( window );
141
// while ( window->parentWidget() != 0 ) {
142
// window = window->parentWidget();
145
return QGuiApplication::focusWindow()->winId();
149
void Session::setDarkBackground(bool darkBackground)
151
_hasDarkBackground = darkBackground;
153
bool Session::hasDarkBackground() const
155
return _hasDarkBackground;
157
bool Session::isRunning() const
159
return _shellProcess->state() == QProcess::Running;
162
void Session::setCodec(QTextCodec * codec)
164
emulation()->setCodec(codec);
167
void Session::setProgram(const QString & program)
169
_program = ShellCommand::expand(program);
171
void Session::setInitialWorkingDirectory(const QString & dir)
173
_initialWorkingDir = ShellCommand::expand(dir);
175
void Session::setArguments(const QStringList & arguments)
177
_arguments = ShellCommand::expand(arguments);
180
QList<KTerminalDisplay *> Session::views() const
185
void Session::addView(KTerminalDisplay * widget)
187
Q_ASSERT( !_views.contains(widget) );
189
_views.append(widget);
191
if ( _emulation != 0 ) {
192
// connect emulation - view signals and slots
193
connect( widget , SIGNAL(keyPressedSignal(QKeyEvent *)) , _emulation ,
194
SLOT(sendKeyEvent(QKeyEvent *)) );
195
// connect( widget , SIGNAL(mouseSignal(int,int,int,int)) , _emulation ,
196
// SLOT(sendMouseEvent(int,int,int,int)) );
197
// connect( widget , SIGNAL(sendStringToEmu(const char *)) , _emulation ,
198
// SLOT(sendString(const char *)) );
200
// allow emulation to notify view when the foreground process
201
// indicates whether or not it is interested in mouse signals
202
// connect( _emulation , SIGNAL(programUsesMouseChanged(bool)) , widget ,
203
// SLOT(setUsesMouse(bool)) );
205
//widget->setUsesMouse( _emulation->programUsesMouse() );
207
widget->setScreenWindow(_emulation->createWindow());
210
//connect view signals and slots
211
QObject::connect( widget ,SIGNAL(changedContentSizeSignal(int,int)),this,
212
SLOT(onViewSizeChange(int,int)));
214
QObject::connect( widget ,SIGNAL(destroyed(QObject *)) , this ,
215
SLOT(viewDestroyed(QObject *)) );
217
//QObject::connect(this, SIGNAL(finished()), widget, SLOT(close()));
221
void Session::viewDestroyed(QObject * view)
223
KTerminalDisplay * display = (KTerminalDisplay *)view;
225
Q_ASSERT( _views.contains(display) );
230
void Session::removeView(KTerminalDisplay * widget)
232
_views.removeAll(widget);
234
disconnect(widget,0,this,0);
236
if ( _emulation != 0 ) {
238
// - key presses signals from widget
239
// - mouse activity signals from widget
240
// - string sending signals from widget
242
// ... and any other signals connected in addView()
243
disconnect( widget, 0, _emulation, 0);
245
// disconnect state change signals emitted by emulation
246
disconnect( _emulation , 0 , widget , 0);
249
// close the session automatically when the last view is removed
250
if ( _views.count() == 0 ) {
257
//check that everything is in place to run the session
258
// if (_program.isEmpty()) {
259
// qDebug() << "Session::run() - program to run not set.";
262
// qDebug() << "Session::run() - program:" << _program;
265
// if (_arguments.isEmpty()) {
266
// qDebug() << "Session::run() - no command line arguments specified.";
269
// qDebug() << "Session::run() - arguments:" << _arguments;
272
// Upon a KPty error, there is no description on what that error was...
273
// Check to see if the given program is executable.
276
/* ok iam not exactly sure where _program comes from - however it was set to /bin/bash on my system
277
* Thats bad for BSD as its /usr/local/bin/bash there - its also bad for arch as its /usr/bin/bash there too!
278
* So i added a check to see if /bin/bash exists - if no then we use $SHELL - if that does not exist either, we fall back to /bin/sh
279
* As far as i know /bin/sh exists on every unix system.. You could also just put some ifdef __FREEBSD__ here but i think these 2 filechecks are worth
280
* their computing time on any system - especially with the problem on arch linux beeing there too.
282
QString exec = QFile::encodeName(_program);
283
// if 'exec' is not specified, fall back to default shell. if that
284
// is not set then fall back to /bin/sh
286
// here we expect full path. If there is no fullpath let's expect it's
287
// a custom shell (eg. python, etc.) available in the PATH.
288
if (exec.startsWith("/"))
291
if ( exec.isEmpty() || !excheck.exists() ) {
292
exec = getenv("SHELL");
294
excheck.setFileName(exec);
296
if ( exec.isEmpty() || !excheck.exists() ) {
301
// _arguments sometimes contain ("") so isEmpty()
302
// or count() does not work as expected...
303
QString argsTmp(_arguments.join(" ").trimmed());
304
QStringList arguments;
306
if (argsTmp.length())
307
arguments << _arguments;
309
QString cwd = QDir::currentPath();
310
if (!_initialWorkingDir.isEmpty()) {
311
_shellProcess->setWorkingDirectory(_initialWorkingDir);
313
_shellProcess->setWorkingDirectory(cwd);
316
_shellProcess->setFlowControlEnabled(_flowControl);
317
_shellProcess->setErase(_emulation->eraseChar());
319
// this is not strictly accurate use of the COLORFGBG variable. This does not
320
// tell the terminal exactly which colors are being used, but instead approximates
321
// the color scheme as "black on white" or "white on black" depending on whether
322
// the background color is deemed dark or not
323
QString backgroundColorHint = _hasDarkBackground ? "COLORFGBG=15;0" : "COLORFGBG=0;15";
325
/* if we do all the checking if this shell exists then we use it ;)
326
* Dont know about the arguments though.. maybe youll need some more checking im not sure
327
* However this works on Arch and FreeBSD now.
329
int result = _shellProcess->start(exec,
331
_environment << backgroundColorHint,
336
qDebug() << "CRASHED! result: " << result;
340
_shellProcess->setWriteable(false); // We are reachable via kwrited.
341
//qDebug() << "started!";
345
void Session::setUserTitle( int what, const QString & caption )
347
//set to true if anything is actually changed (eg. old _nameTitle != new _nameTitle )
348
bool modified = false;
350
// (btw: what=0 changes _userTitle and icon, what=1 only icon, what=2 only _nameTitle
351
if ((what == 0) || (what == 2)) {
352
if ( _userTitle != caption ) {
353
_userTitle = caption;
358
if ((what == 0) || (what == 1)) {
359
if ( _iconText != caption ) {
366
QString colorString = caption.section(';',0,0);
367
qDebug() << __FILE__ << __LINE__ << ": setting background colour to " << colorString;
368
QColor backColor = QColor(colorString);
369
if (backColor.isValid()) { // change color via \033]11;Color\007
370
if (backColor != _modifiedBackground) {
371
_modifiedBackground = backColor;
373
// bail out here until the code to connect the terminal display
374
// to the changeBackgroundColor() signal has been written
375
// and tested - just so we don't forget to do this.
378
emit changeBackgroundColorRequest(backColor);
384
if ( _nameTitle != caption ) {
385
setTitle(Session::NameRole,caption);
392
cwd=cwd.replace( QRegExp("^~"), QDir::homePath() );
393
emit openUrlRequest(cwd);
396
// change icon via \033]32;Icon\007
398
if ( _iconName != caption ) {
406
emit profileChangeCommandReceived(caption);
415
QString Session::userTitle() const
419
void Session::setTabTitleFormat(TabTitleContext context , const QString & format)
421
if ( context == LocalTabTitle ) {
422
_localTabTitleFormat = format;
423
} else if ( context == RemoteTabTitle ) {
424
_remoteTabTitleFormat = format;
427
QString Session::tabTitleFormat(TabTitleContext context) const
429
if ( context == LocalTabTitle ) {
430
return _localTabTitleFormat;
431
} else if ( context == RemoteTabTitle ) {
432
return _remoteTabTitleFormat;
438
void Session::monitorTimerDone()
440
//FIXME: The idea here is that the notification popup will appear to tell the user than output from
441
//the terminal has stopped and the popup will disappear when the user activates the session.
443
//This breaks with the addition of multiple views of a session. The popup should disappear
444
//when any of the views of the session becomes active
447
//FIXME: Make message text for this notification and the activity notification more descriptive.
448
if (_monitorSilence) {
449
// KNotification::event("Silence", ("Silence in session '%1'", _nameTitle), QPixmap(),
450
// QApplication::activeWindow(),
451
// KNotification::CloseWhenWidgetActivated);
452
emit stateChanged(NOTIFYSILENCE);
454
emit stateChanged(NOTIFYNORMAL);
457
_notifiedActivity=false;
460
void Session::activityStateSet(int state)
462
if (state==NOTIFYBELL) {
464
s.sprintf("Bell in session '%s'",_nameTitle.toLatin1().data());
466
emit bellRequest( s );
467
} else if (state==NOTIFYACTIVITY) {
468
if (_monitorSilence) {
469
_monitorTimer->start(_silenceSeconds*1000);
472
if ( _monitorActivity ) {
473
//FIXME: See comments in Session::monitorTimerDone()
474
if (!_notifiedActivity) {
475
// KNotification::event("Activity", ("Activity in session '%1'", _nameTitle), QPixmap(),
476
// QApplication::activeWindow(),
477
// KNotification::CloseWhenWidgetActivated);
478
_notifiedActivity=true;
483
if ( state==NOTIFYACTIVITY && !_monitorActivity ) {
484
state = NOTIFYNORMAL;
486
if ( state==NOTIFYSILENCE && !_monitorSilence ) {
487
state = NOTIFYNORMAL;
490
emit stateChanged(state);
493
void Session::onViewSizeChange(int /*height*/, int /*width*/)
495
updateTerminalSize();
497
void Session::onEmulationSizeChange(int lines , int columns)
499
setSize( QSize(lines,columns) );
502
void Session::updateTerminalSize()
504
QListIterator<KTerminalDisplay *> viewIter(_views);
509
// minimum number of lines and columns that views require for
510
// their size to be taken into consideration ( to avoid problems
511
// with new view widgets which haven't yet been set to their correct size )
512
const int VIEW_LINES_THRESHOLD = 2;
513
const int VIEW_COLUMNS_THRESHOLD = 2;
515
//select largest number of lines and columns that will fit in all visible views
516
while ( viewIter.hasNext() ) {
517
KTerminalDisplay * view = viewIter.next();
518
if ( view->lines() >= VIEW_LINES_THRESHOLD &&
519
view->columns() >= VIEW_COLUMNS_THRESHOLD ) {
520
minLines = (minLines == -1) ? view->lines() : qMin( minLines , view->lines() );
521
minColumns = (minColumns == -1) ? view->columns() : qMin( minColumns , view->columns() );
525
// backend emulation must have a _terminal of at least 1 column x 1 line in size
526
if ( minLines > 0 && minColumns > 0 ) {
527
_emulation->setImageSize( minLines , minColumns );
528
_shellProcess->setWindowSize( minLines , minColumns );
532
void Session::refresh()
534
// attempt to get the shell process to redraw the display
536
// this requires the program running in the shell
537
// to cooperate by sending an update in response to
538
// a window size change
540
// the window size is changed twice, first made slightly larger and then
541
// resized back to its normal size so that there is actually a change
542
// in the window size (some shells do nothing if the
543
// new and old sizes are the same)
545
// if there is a more 'correct' way to do this, please
546
// send an email with method or patches to konsole-devel@kde.org
548
const QSize existingSize = _shellProcess->windowSize();
549
_shellProcess->setWindowSize(existingSize.height(),existingSize.width()+1);
550
_shellProcess->setWindowSize(existingSize.height(),existingSize.width());
553
bool Session::sendSignal(int signal)
555
int result = ::kill(_shellProcess->pid(),signal);
559
_shellProcess->waitForFinished();
566
void Session::close()
570
if (!_shellProcess->isRunning() || !sendSignal(SIGHUP)) {
572
QTimer::singleShot(1, this, SIGNAL(finished()));
576
void Session::sendText(const QString &text) const
578
_emulation->sendText(text);
581
void Session::sendKey(QKeyEvent *key)
583
_emulation->sendKeyEvent(key);
589
delete _shellProcess;
590
// delete _zmodemProc;
593
void Session::setProfileKey(const QString & key)
596
emit profileChanged(key);
598
QString Session::profileKey() const
603
void Session::done(int exitStatus)
606
_userTitle = ("This session is done. Finished");
612
if (!_wantedClose || exitStatus != 0) {
614
if (_shellProcess->exitStatus() == QProcess::NormalExit) {
615
message.sprintf("Session '%s' exited with status %d.",
616
_nameTitle.toLatin1().data(), exitStatus);
618
message.sprintf("Session '%s' crashed.",
619
_nameTitle.toLatin1().data());
623
if ( !_wantedClose && _shellProcess->exitStatus() != QProcess::NormalExit )
624
message.sprintf("Session '%s' exited unexpectedly.",
625
_nameTitle.toLatin1().data());
631
Emulation * Session::emulation() const
636
QString Session::keyBindings() const
638
return _emulation->keyBindings();
641
QStringList Session::environment() const
646
void Session::setEnvironment(const QStringList & environment)
648
_environment = environment;
651
int Session::sessionId() const
656
void Session::setKeyBindings(const QString & id)
658
_emulation->setKeyBindings(id);
661
void Session::setTitle(TitleRole role , const QString & newTitle)
663
if ( title(role) != newTitle ) {
664
if ( role == NameRole ) {
665
_nameTitle = newTitle;
666
} else if ( role == DisplayedTitleRole ) {
667
_displayTitle = newTitle;
674
QString Session::title(TitleRole role) const
676
if ( role == NameRole ) {
678
} else if ( role == DisplayedTitleRole ) {
679
return _displayTitle;
685
void Session::setIconName(const QString & iconName)
687
if ( iconName != _iconName ) {
688
_iconName = iconName;
693
void Session::setIconText(const QString & iconText)
695
_iconText = iconText;
696
//kDebug(1211)<<"Session setIconText " << _iconText;
699
QString Session::iconName() const
704
QString Session::iconText() const
709
void Session::setHistoryType(const HistoryType & hType)
711
_emulation->setHistory(hType);
714
const HistoryType & Session::historyType() const
716
return _emulation->history();
719
void Session::clearHistory()
721
_emulation->clearHistory();
724
QStringList Session::arguments() const
729
QString Session::program() const
735
bool Session::isMonitorActivity() const
737
return _monitorActivity;
740
bool Session::isMonitorSilence() const
742
return _monitorSilence;
745
void Session::setMonitorActivity(bool _monitor)
747
_monitorActivity=_monitor;
748
_notifiedActivity=false;
750
activityStateSet(NOTIFYNORMAL);
753
void Session::setMonitorSilence(bool _monitor)
755
if (_monitorSilence==_monitor) {
759
_monitorSilence=_monitor;
760
if (_monitorSilence) {
761
_monitorTimer->start(_silenceSeconds*1000);
763
_monitorTimer->stop();
766
activityStateSet(NOTIFYNORMAL);
769
void Session::setMonitorSilenceSeconds(int seconds)
771
_silenceSeconds=seconds;
772
if (_monitorSilence) {
773
_monitorTimer->start(_silenceSeconds*1000);
777
void Session::setAddToUtmp(bool set)
782
void Session::setFlowControlEnabled(bool enabled)
784
if (_flowControl == enabled) {
788
_flowControl = enabled;
791
_shellProcess->setFlowControlEnabled(_flowControl);
794
emit flowControlEnabledChanged(enabled);
796
bool Session::flowControlEnabled() const
800
//void Session::fireZModemDetected()
804
// QTimer::singleShot(10, this, SIGNAL(zmodemDetected()));
805
// _zmodemBusy = true;
809
//void Session::cancelZModem()
811
// _shellProcess->sendData("\030\030\030\030", 4); // Abort
812
// _zmodemBusy = false;
815
//void Session::startZModem(const QString &zmodem, const QString &dir, const QStringList &list)
817
// _zmodemBusy = true;
818
// _zmodemProc = new KProcess();
819
// _zmodemProc->setOutputChannelMode( KProcess::SeparateChannels );
821
// *_zmodemProc << zmodem << "-v" << list;
823
// if (!dir.isEmpty())
824
// _zmodemProc->setWorkingDirectory(dir);
826
// _zmodemProc->start();
828
// connect(_zmodemProc,SIGNAL (readyReadStandardOutput()),
829
// this, SLOT(zmodemReadAndSendBlock()));
830
// connect(_zmodemProc,SIGNAL (readyReadStandardError()),
831
// this, SLOT(zmodemReadStatus()));
832
// connect(_zmodemProc,SIGNAL (finished(int,QProcess::ExitStatus)),
833
// this, SLOT(zmodemFinished()));
835
// disconnect( _shellProcess,SIGNAL(block_in(const char*,int)), this, SLOT(onReceiveBlock(const char*,int)) );
836
// connect( _shellProcess,SIGNAL(block_in(const char*,int)), this, SLOT(zmodemRcvBlock(const char*,int)) );
838
// _zmodemProgress = new ZModemDialog(QApplication::activeWindow(), false,
839
// i18n("ZModem Progress"));
841
// connect(_zmodemProgress, SIGNAL(user1Clicked()),
842
// this, SLOT(zmodemDone()));
844
// _zmodemProgress->show();
847
/*void Session::zmodemReadAndSendBlock()
849
_zmodemProc->setReadChannel( QProcess::StandardOutput );
850
QByteArray data = _zmodemProc->readAll();
852
if ( data.count() == 0 )
855
_shellProcess->sendData(data.constData(),data.count());
859
void Session::zmodemReadStatus()
861
_zmodemProc->setReadChannel( QProcess::StandardError );
862
QByteArray msg = _zmodemProc->readAll();
863
while(!msg.isEmpty())
865
int i = msg.indexOf('\015');
866
int j = msg.indexOf('\012');
868
if ((i != -1) && ((j == -1) || (i < j)))
883
_zmodemProgress->addProgressText(QString::fromLocal8Bit(txt));
888
void Session::zmodemRcvBlock(const char *data, int len)
890
QByteArray ba( data, len );
892
_zmodemProc->write( ba );
896
void Session::zmodemFinished()
904
disconnect( _shellProcess,SIGNAL(block_in(const char*,int)), this ,SLOT(zmodemRcvBlock(const char*,int)) );
905
connect( _shellProcess,SIGNAL(block_in(const char*,int)), this, SLOT(onReceiveBlock(const char*,int)) );
907
_shellProcess->sendData("\030\030\030\030", 4); // Abort
908
_shellProcess->sendData("\001\013\n", 3); // Try to get prompt back
909
_zmodemProgress->transferDone();
913
void Session::onReceiveBlock( const char * buf, int len )
915
_emulation->receiveData( buf, len );
916
emit receivedData( QString::fromLatin1( buf, len ) );
919
QSize Session::size()
921
return _emulation->imageSize();
924
void Session::setSize(const QSize & size)
926
if ((size.width() <= 1) || (size.height() <= 1)) {
930
emit resizeRequest(size);
932
int Session::foregroundProcessId() const
934
return _shellProcess->foregroundProcessGroup();
936
int Session::processId() const
938
return _shellProcess->pid();
941
SessionGroup::SessionGroup()
945
SessionGroup::~SessionGroup()
950
int SessionGroup::masterMode() const
954
QList<Session *> SessionGroup::sessions() const
956
return _sessions.keys();
958
bool SessionGroup::masterStatus(Session * session) const
960
return _sessions[session];
963
void SessionGroup::addSession(Session * session)
965
_sessions.insert(session,false);
967
QListIterator<Session *> masterIter(masters());
969
while ( masterIter.hasNext() ) {
970
connectPair(masterIter.next(),session);
973
void SessionGroup::removeSession(Session * session)
975
setMasterStatus(session,false);
977
QListIterator<Session *> masterIter(masters());
979
while ( masterIter.hasNext() ) {
980
disconnectPair(masterIter.next(),session);
983
_sessions.remove(session);
985
void SessionGroup::setMasterMode(int mode)
992
QList<Session *> SessionGroup::masters() const
994
return _sessions.keys(true);
996
void SessionGroup::connectAll(bool connect)
998
QListIterator<Session *> masterIter(masters());
1000
while ( masterIter.hasNext() ) {
1001
Session * master = masterIter.next();
1003
QListIterator<Session *> otherIter(_sessions.keys());
1004
while ( otherIter.hasNext() ) {
1005
Session * other = otherIter.next();
1007
if ( other != master ) {
1009
connectPair(master,other);
1011
disconnectPair(master,other);
1017
void SessionGroup::setMasterStatus(Session * session, bool master)
1019
bool wasMaster = _sessions[session];
1020
_sessions[session] = master;
1022
if ((!wasMaster && !master)
1023
|| (wasMaster && master)) {
1027
QListIterator<Session *> iter(_sessions.keys());
1028
while (iter.hasNext()) {
1029
Session * other = iter.next();
1031
if (other != session) {
1033
connectPair(session, other);
1035
disconnectPair(session, other);
1041
void SessionGroup::connectPair(Session * master , Session * other)
1043
// qDebug() << k_funcinfo;
1045
if ( _masterMode & CopyInputToAll ) {
1046
qDebug() << "Connection session " << master->nameTitle() << "to" << other->nameTitle();
1048
connect( master->emulation() , SIGNAL(sendData(const char *,int)) , other->emulation() ,
1049
SLOT(sendString(const char *,int)) );
1052
void SessionGroup::disconnectPair(Session * master , Session * other)
1054
// qDebug() << k_funcinfo;
1056
if ( _masterMode & CopyInputToAll ) {
1057
qDebug() << "Disconnecting session " << master->nameTitle() << "from" << other->nameTitle();
1059
disconnect( master->emulation() , SIGNAL(sendData(const char *,int)) , other->emulation() ,
1060
SLOT(sendString(const char *,int)) );
1064
//#include "moc_Session.cpp"