File indexing completed on 2025-01-19 04:23:28
0001 /* 0002 This file is part of Konsole QML plugin, 0003 which is a terminal emulator from KDE. 0004 0005 Copyright 2013 by Dmitry Zagnoyko <hiroshidi@gmail.com> 0006 0007 This program is free software; you can redistribute it and/or modify 0008 it under the terms of the GNU General Public License as published by 0009 the Free Software Foundation; either version 2 of the License, or 0010 (at your option) any later version. 0011 0012 This program is distributed in the hope that it will be useful, 0013 but WITHOUT ANY WARRANTY; without even the implied warranty of 0014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0015 GNU General Public License for more details. 0016 0017 You should have received a copy of the GNU General Public License 0018 along with this program; if not, write to the Free Software 0019 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 0020 02110-1301 USA. 0021 */ 0022 0023 // Own 0024 #include "ksession.h" 0025 #include <KShell> 0026 0027 // Qt 0028 #include <QTextCodec> 0029 #include <QDir> 0030 #include <QDebug> 0031 0032 // Konsole 0033 #include "KeyboardTranslator.h" 0034 #include "HistorySearch.h" 0035 #include "History.h" 0036 0037 #include "Emulation.h" 0038 0039 KSession::KSession(QObject *parent) : 0040 QObject(parent), m_session(createSession("")) 0041 { 0042 connect(m_session, SIGNAL(started()), this, SIGNAL(started())); 0043 connect(m_session, SIGNAL(finished()), this, SLOT(sessionFinished())); 0044 connect(m_session, SIGNAL(titleChanged()), this, SIGNAL(titleChanged())); 0045 connect(m_session, &Session::stateChanged, [this](int state) 0046 { 0047 qDebug() << m_session->iconText() << m_session->iconName() << m_session->isMonitorSilence() << m_session->program() << state; 0048 Q_EMIT hasActiveProcessChanged(); 0049 0050 if(m_processName != m_session->foregroundProcessName()) 0051 { 0052 m_processName = m_session->foregroundProcessName(); 0053 Q_EMIT foregroundProcessNameChanged(); 0054 } 0055 }); 0056 0057 // m_session->setMonitorSilence(true); 0058 m_session->setMonitorSilenceSeconds(30); 0059 0060 connect(m_session, &Session::bellRequest, [this](QString message) 0061 { 0062 Q_EMIT bellRequest(message); 0063 }); 0064 0065 connect(m_session, &Session::changeTabTextColorRequest, [this](int state) 0066 { 0067 qDebug() << "changeTabTextColorRequest" << state; 0068 }); 0069 0070 connect(m_session, &Session::changeTabTextColorRequest, [this](int state) 0071 { 0072 qDebug() << "changeTabTextColorRequest" << state; 0073 }); 0074 0075 connect(m_session, &Session::changeBackgroundColorRequest, [this](QColor state) 0076 { 0077 qDebug() << "changeBackgroundColorRequest" << state; 0078 }); 0079 0080 connect(m_session, &Session::openUrlRequest, [this](QString state) 0081 { 0082 qDebug() << "openUrlRequest" << state; 0083 }); 0084 0085 connect(m_session, &Session::activity, [this]() 0086 { 0087 qDebug() << "activity"; 0088 Q_EMIT processHasSilent(false); 0089 }); 0090 0091 connect(m_session, &Session::silence, [this]() 0092 { 0093 qDebug() << "silence"; 0094 Q_EMIT processHasSilent(true); 0095 }); 0096 } 0097 0098 KSession::~KSession() 0099 { 0100 if (m_session) { 0101 m_session->close(); 0102 m_session->disconnect(); 0103 delete m_session; 0104 } 0105 } 0106 0107 void KSession::setMonitorSilence(bool value) 0108 { 0109 if(m_session->isMonitorSilence() == value) 0110 return; 0111 0112 m_session->setMonitorSilence(value); 0113 Q_EMIT monitorSilenceChanged(); 0114 } 0115 0116 bool KSession::monitorSilence() const 0117 { 0118 return m_session->isMonitorSilence(); 0119 } 0120 0121 void KSession::setTitle(QString name) 0122 { 0123 m_session->setTitle(Session::NameRole, name); 0124 } 0125 0126 Session *KSession::createSession(QString name) 0127 { 0128 Session *session = new Session(); 0129 0130 session->setTitle(Session::NameRole, name); 0131 0132 /* Thats a freaking bad idea!!!! 0133 * /bin/bash is not there on every system 0134 * better set it to the current $SHELL 0135 * Maybe you can also make a list available and then let the widget-owner decide what to use. 0136 * By setting it to $SHELL right away we actually make the first filecheck obsolete. 0137 * But as iam not sure if you want to do anything else ill just let both checks in and set this to $SHELL anyway. 0138 */ 0139 0140 //cool-old-term: There is another check in the code. Not sure if useful. 0141 0142 QString envshell = getenv("SHELL"); 0143 QString shellProg = envshell != NULL ? envshell : "/bin/bash"; 0144 session->setProgram(shellProg); 0145 0146 setenv("TERM", "xterm-256color", 1); 0147 0148 //session->setProgram(); 0149 0150 QStringList args(""); 0151 session->setArguments(args); 0152 session->setAutoClose(true); 0153 0154 session->setCodec(QTextCodec::codecForName("UTF-8")); 0155 0156 session->setFlowControlEnabled(true); 0157 session->setHistoryType(HistoryTypeBuffer(1000)); 0158 0159 session->setDarkBackground(true); 0160 0161 session->setKeyBindings(""); 0162 0163 return session; 0164 } 0165 0166 ///////////////////////////////////////////////////////////////////////////////////// 0167 ///////////////////////////////////////////////////////////////////////////////////// 0168 0169 0170 int KSession::getRandomSeed() 0171 { 0172 return m_session->sessionId() * 31; 0173 } 0174 0175 void KSession::addView(TerminalDisplay *display) 0176 { 0177 m_session->addView(display); 0178 } 0179 0180 void KSession::removeView(TerminalDisplay *display) 0181 { 0182 m_session->removeView(display); 0183 } 0184 0185 void KSession::sessionFinished() 0186 { 0187 Q_EMIT finished(); 0188 } 0189 0190 void KSession::selectionChanged(bool textSelected) 0191 { 0192 Q_UNUSED(textSelected) 0193 } 0194 0195 void KSession::startShellProgram() 0196 { 0197 if ( m_session->isRunning() ) { 0198 return; 0199 } 0200 0201 m_session->run(); 0202 } 0203 0204 bool KSession::sendSignal(int signal) 0205 { 0206 if ( !m_session->isRunning() ) { 0207 return false; 0208 } 0209 0210 return m_session->sendSignal(signal); 0211 } 0212 0213 int KSession::getShellPID() 0214 { 0215 return m_session->processId(); 0216 } 0217 0218 void KSession::changeDir(const QString &dir) 0219 { 0220 /* 0221 this is a very hackish way of trying to determine if the shell is in 0222 the foreground before attempting to change the directory. It may not 0223 be portable to anything other than Linux. 0224 */ 0225 QString strCmd; 0226 strCmd.setNum(getShellPID()); 0227 strCmd.prepend("ps -j "); 0228 strCmd.append(" | tail -1 | awk '{ print $5 }' | grep -q \\+"); 0229 int retval = system(strCmd.toStdString().c_str()); 0230 0231 if (!retval) { 0232 // Send prior Ctrl-E, Ctrl-U to ensure the line is empty. This is 0233 // mandatory, otherwise sending a 'cd x\n' to a prompt with 'rm -rf *' 0234 // would result in data loss. 0235 sendText(QStringLiteral("\x05\x15")); 0236 0237 sendText(" cd " + KShell::quoteArg(dir) + '\r'); 0238 Q_EMIT currentDirChanged(); 0239 } 0240 } 0241 0242 void KSession::setEnvironment(const QStringList &environment) 0243 { 0244 m_session->setEnvironment(environment); 0245 } 0246 0247 0248 void KSession::setShellProgram(const QString &progname) 0249 { 0250 m_session->setProgram(progname); 0251 } 0252 0253 void KSession::setInitialWorkingDirectory(const QString &dir) 0254 { 0255 if ( _initialWorkingDirectory != dir ) { 0256 _initialWorkingDirectory = dir; 0257 m_session->setInitialWorkingDirectory(dir); 0258 Q_EMIT initialWorkingDirectoryChanged(); 0259 Q_EMIT currentDirChanged(); 0260 } } 0261 0262 QString KSession::getInitialWorkingDirectory() 0263 { 0264 return _initialWorkingDirectory; 0265 } 0266 0267 void KSession::setArgs(const QStringList &args) 0268 { 0269 m_session->setArguments(args); 0270 } 0271 0272 void KSession::setTextCodec(QTextCodec *codec) 0273 { 0274 m_session->setCodec(codec); 0275 } 0276 0277 void KSession::setHistorySize(int lines) 0278 { 0279 if ( historySize() != lines ) { 0280 if (lines < 0) 0281 m_session->setHistoryType(HistoryTypeFile()); 0282 else 0283 m_session->setHistoryType(HistoryTypeBuffer(lines)); 0284 Q_EMIT historySizeChanged(); 0285 } 0286 } 0287 0288 int KSession::historySize() const 0289 { 0290 if ( m_session->historyType().isUnlimited() ) { 0291 return -1; 0292 } else { 0293 return m_session->historyType().maximumLineCount(); 0294 } 0295 } 0296 0297 QString KSession::getHistory() const 0298 { 0299 QString history; 0300 QTextStream historyStream(&history); 0301 PlainTextDecoder historyDecoder; 0302 0303 historyDecoder.begin(&historyStream); 0304 m_session->emulation()->writeToStream(&historyDecoder); 0305 historyDecoder.end(); 0306 0307 return history; 0308 } 0309 0310 void KSession::sendText(QString text) 0311 { 0312 m_session->sendText(text); 0313 } 0314 0315 void KSession::sendKey(int rep, int key, int mod) const 0316 { 0317 Q_UNUSED(rep); 0318 Q_UNUSED(key); 0319 Q_UNUSED(mod); 0320 0321 //TODO implement or remove this function. 0322 // Qt::KeyboardModifier kbm = Qt::KeyboardModifier(mod); 0323 0324 // QKeyEvent qkey(QEvent::KeyPress, key, kbm); 0325 0326 // while (rep > 0){ 0327 // m_session->sendKey(&qkey); 0328 // --rep; 0329 // } 0330 } 0331 0332 void KSession::clearScreen() 0333 { 0334 m_session->emulation()->clearEntireScreen(); 0335 } 0336 0337 void KSession::search(const QString ®exp, int startLine, int startColumn, bool forwards) 0338 { 0339 HistorySearch *history = new HistorySearch( QPointer<Emulation>(m_session->emulation()), QRegExp(regexp), forwards, startColumn, startLine, this); 0340 connect( history, SIGNAL(matchFound(int,int,int,int)), this, SIGNAL(matchFound(int,int,int,int))); 0341 connect( history, SIGNAL(noMatchFound()), this, SIGNAL(noMatchFound())); 0342 history->search(); 0343 } 0344 0345 void KSession::setFlowControlEnabled(bool enabled) 0346 { 0347 m_session->setFlowControlEnabled(enabled); 0348 } 0349 0350 bool KSession::flowControlEnabled() 0351 { 0352 return m_session->flowControlEnabled(); 0353 } 0354 0355 void KSession::setKeyBindings(const QString &kb) 0356 { 0357 m_session->setKeyBindings(kb); 0358 Q_EMIT changedKeyBindings(kb); 0359 } 0360 0361 QString KSession::getKeyBindings() 0362 { 0363 return m_session->keyBindings(); 0364 } 0365 0366 QStringList KSession::availableKeyBindings() 0367 { 0368 return KeyboardTranslatorManager::instance()->allTranslators(); 0369 } 0370 0371 QString KSession::keyBindings() 0372 { 0373 return m_session->keyBindings(); 0374 } 0375 0376 QString KSession::getTitle() 0377 { 0378 // if (m_session->currentDir() == QDir::homePath()) { 0379 // return m_session->currentDir(); 0380 // } 0381 // 0382 // if (m_session->currentDir() == "/") 0383 // return m_session->currentDir(); 0384 // 0385 // return QDir(m_session->currentDir()).dirName(); 0386 0387 return m_session->userTitle(); 0388 } 0389 0390 bool KSession::hasActiveProcess() const 0391 { 0392 return m_session->processId() != m_session->foregroundProcessId(); 0393 } 0394 0395 QString KSession::foregroundProcessName() 0396 { 0397 return m_session->foregroundProcessName(); 0398 } 0399 0400 QString KSession::currentDir() 0401 { 0402 return m_session->currentDir(); 0403 }