diff --git a/src/Application.cpp b/src/Application.cpp index 1c359a9db..7bbc38fc1 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -103,49 +103,56 @@ void Application::listAvailableProfiles() int Application::newInstance() { KCmdLineArgs* args = KCmdLineArgs::parsedArgs(); + static bool firstInstance = true; - // check for arguments to print help or other information to the terminal, - // quit if such an argument was found - if ( processHelpArgs(args) ) - return 0; - - // create a new window or use an existing one - MainWindow* window = processWindowArgs(args); - - // select profile to use - processProfileSelectArgs(args,window); - - // process various command-line options which cause a property of the - // default profile to be changed - processProfileChangeArgs(args,window); - - // create new session - Session* session = createSession( window->defaultProfile() , QString() , window->viewManager() ); - if ( !args->isSet("close") ) - session->setAutoClose(false); - - // if the background-mode argument is supplied, start the background session - // ( or bring to the front if it already exists ) - if ( args->isSet("background-mode") ) - startBackgroundMode(window); - else + // handle session management + if ((args->count() != 0) || !firstInstance || !isSessionRestored()) { - // Qt constrains top-level windows which have not been manually resized - // (via QWidget::resize()) to a maximum of 2/3rds of the screen size. - // - // This means that the terminal display might not get the width/height - // it asks for. To work around this, the widget must be manually resized - // to its sizeHint(). - // - // This problem only affects the first time the application is run. After - // that KMainWindow will have manually resized the window to its saved size - // at this point (so the Qt::WA_Resized attribute will be set) - if (!window->testAttribute(Qt::WA_Resized)) - window->resize(window->sizeHint()); + // check for arguments to print help or other information to the terminal, + // quit if such an argument was found + if ( processHelpArgs(args) ) + return 0; - window->show(); + // create a new window or use an existing one + MainWindow* window = processWindowArgs(args); + + // select profile to use + processProfileSelectArgs(args,window); + + // process various command-line options which cause a property of the + // default profile to be changed + processProfileChangeArgs(args,window); + + // create new session + Session* session = createSession( window->defaultProfile() , QString() , window->viewManager() ); + if ( !args->isSet("close") ) + session->setAutoClose(false); + + // if the background-mode argument is supplied, start the background session + // ( or bring to the front if it already exists ) + if ( args->isSet("background-mode") ) + startBackgroundMode(window); + else + { + // Qt constrains top-level windows which have not been manually resized + // (via QWidget::resize()) to a maximum of 2/3rds of the screen size. + // + // This means that the terminal display might not get the width/height + // it asks for. To work around this, the widget must be manually resized + // to its sizeHint(). + // + // This problem only affects the first time the application is run. After + // that KMainWindow will have manually resized the window to its saved size + // at this point (so the Qt::WA_Resized attribute will be set) + if (!window->testAttribute(Qt::WA_Resized)) + window->resize(window->sizeHint()); + + window->show(); + } } + firstInstance = false; + args->clear(); return 0; } @@ -313,3 +320,12 @@ Session* Application::createSession(Profile::Ptr profile, const QString& directo } #include "Application.moc" + +/* + Local Variables: + mode: c++ + c-file-style: "stroustrup" + indent-tabs-mode: nil + tab-width: 4 + End: +*/ diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index 61174bf1e..dcfeef2b8 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -19,6 +19,7 @@ // Own #include "MainWindow.h" +#include "SessionManager.h" // Qt #include @@ -378,6 +379,33 @@ bool MainWindow::queryClose() return true; } + +void MainWindow::saveProperties(KConfigGroup& group) +{ + group.writePathEntry("Default Profile", _defaultProfile->path()); + _viewManager->saveSessions(group); +} + +void MainWindow::readProperties(const KConfigGroup& group) +{ + SessionManager *manager = SessionManager::instance(); + QString profile = group.readPathEntry("Default Profile", QString()); + Profile::Ptr ptr = manager->defaultProfile(); + if (!profile.isEmpty()) ptr = manager->loadProfile(profile); + setDefaultProfile(ptr); + _viewManager->restoreSessions(group); +} + +void MainWindow::saveGlobalProperties(KConfig* config) +{ + SessionManager::instance()->saveSessions(config); +} + +void MainWindow::readGlobalProperties(KConfig* config) +{ + SessionManager::instance()->restoreSessions(config); +} + void MainWindow::syncActiveShortcuts(KActionCollection* dest, const KActionCollection* source) { foreach(QAction* qAction, source->actions()) @@ -456,3 +484,12 @@ void MainWindow::configureNotifications() } #include "MainWindow.moc" + +/* + Local Variables: + mode: c++ + c-file-style: "stroustrup" + indent-tabs-mode: nil + tab-width: 4 + End: +*/ diff --git a/src/MainWindow.h b/src/MainWindow.h index 325f9fd22..c55ae551a 100644 --- a/src/MainWindow.h +++ b/src/MainWindow.h @@ -132,6 +132,10 @@ class MainWindow : public KXmlGuiWindow protected: // reimplemented from KMainWindow virtual bool queryClose(); + virtual void saveProperties(KConfigGroup& group); + virtual void readProperties(const KConfigGroup& group); + virtual void saveGlobalProperties(KConfig* config); + virtual void readGlobalProperties(KConfig* config); private slots: void newTab(); @@ -179,3 +183,12 @@ class MainWindow : public KXmlGuiWindow } #endif // KONSOLEMAINWINDOW_H + +/* + Local Variables: + mode: c++ + c-file-style: "stroustrup" + indent-tabs-mode: nil + tab-width: 4 + End: +*/ diff --git a/src/ProcessInfo.cpp b/src/ProcessInfo.cpp index abf0a9d39..27bc2fd98 100644 --- a/src/ProcessInfo.cpp +++ b/src/ProcessInfo.cpp @@ -64,18 +64,10 @@ void ProcessInfo::update() readProcessInfo(_pid,_enableEnvironmentRead); } -QString ProcessInfo::format(const QString& input) const +QString ProcessInfo::validCurrentDir() const { bool ok = false; - QString output(input); - - // search for and replace known marker - output.replace("%u","NOT IMPLEMENTED YET"); - output.replace("%n",name(&ok)); - output.replace("%c",formatCommand(name(&ok),arguments(&ok),ShortCommandFormat)); - output.replace("%C",formatCommand(name(&ok),arguments(&ok),LongCommandFormat)); - // read current dir, if an error occurs try the parent as the next // best option int currentPid = parentPid(&ok); @@ -88,7 +80,23 @@ QString ProcessInfo::format(const QString& input) const dir = current->currentDir(&ok); delete current; } - + + return dir; +} + +QString ProcessInfo::format(const QString& input) const +{ + bool ok = false; + + QString output(input); + + // search for and replace known marker + output.replace("%u","NOT IMPLEMENTED YET"); + output.replace("%n",name(&ok)); + output.replace("%c",formatCommand(name(&ok),arguments(&ok),ShortCommandFormat)); + output.replace("%C",formatCommand(name(&ok),arguments(&ok),LongCommandFormat)); + + QString dir = validCurrentDir(); output.replace("%D",dir); output.replace("%d",formatShortDir(dir)); @@ -731,3 +739,11 @@ ProcessInfo* ProcessInfo::newInstance(int pid,bool enableEnvironmentRead) #endif } +/* + Local Variables: + mode: c++ + c-file-style: "stroustrup" + indent-tabs-mode: nil + tab-width: 4 + End: +*/ diff --git a/src/ProcessInfo.h b/src/ProcessInfo.h index 766a4346e..47876e6d1 100644 --- a/src/ProcessInfo.h +++ b/src/ProcessInfo.h @@ -151,6 +151,11 @@ public: */ QString currentDir(bool* ok) const; + /** + * Returns the current working directory of the process (or its parent) + */ + QString validCurrentDir() const; + /** * Parses an input string, looking for markers beginning with a '%' * character and returns a string with the markers replaced @@ -424,3 +429,12 @@ private: } #endif //PROCESSINFO_H + +/* + Local Variables: + mode: c++ + c-file-style: "stroustrup" + indent-tabs-mode: nil + tab-width: 4 + End: +*/ diff --git a/src/Session.cpp b/src/Session.cpp index 1dd5c1002..195df0671 100644 --- a/src/Session.cpp +++ b/src/Session.cpp @@ -48,11 +48,13 @@ #include #include #include +#include // Konsole #include #include +#include "ProcessInfo.h" #include "Pty.h" #include "TerminalDisplay.h" #include "ShellCommand.h" @@ -77,6 +79,9 @@ Session::Session(QObject* parent) : , _flowControl(true) , _fullScripting(false) , _sessionId(0) + , _sessionProcessInfo(0) + , _foregroundProcessInfo(0) + , _foregroundPid(0) , _zmodemBusy(false) , _zmodemProc(0) , _zmodemProgress(0) @@ -200,6 +205,19 @@ void Session::setArguments(const QStringList& arguments) _arguments = ShellCommand::expand(arguments); } +QString Session::currentWorkingDirectory() +{ + // only returned cached value + if (_currentWorkingDir.isEmpty()) updateWorkingDirectory(); + return _currentWorkingDir; +} +ProcessInfo* Session::updateWorkingDirectory() +{ + ProcessInfo *process = getProcessInfo(); + _currentWorkingDir = process->validCurrentDir(); + return process; +} + QList Session::views() const { return _views; @@ -322,9 +340,13 @@ void Session::run() { //check that everything is in place to run the session if (_program.isEmpty()) + { kDebug() << "Session::run() - program to run not set."; + } if (_arguments.isEmpty()) + { kDebug() << "Session::run() - no command line arguments specified."; + } const int CHOICE_COUNT = 3; QString programs[CHOICE_COUNT] = {_program,qgetenv("SHELL"),"/bin/sh"}; @@ -662,6 +684,10 @@ void Session::sendText(const QString &text) const Session::~Session() { + if (_foregroundProcessInfo) + delete _foregroundProcessInfo; + if (_sessionProcessInfo) + delete _sessionProcessInfo; delete _emulation; delete _shellProcess; delete _zmodemProc; @@ -749,6 +775,110 @@ QString Session::title(TitleRole role) const return QString(); } +ProcessInfo* Session::getProcessInfo() +{ + ProcessInfo* process; + + if (isChildActive()) + process = _foregroundProcessInfo; + else + { + updateSessionProcessInfo(); + process = _sessionProcessInfo; + } + + return process; +} + +void Session::updateSessionProcessInfo() +{ + Q_ASSERT(_shellProcess); + if (!_sessionProcessInfo) + _sessionProcessInfo = ProcessInfo::newInstance(processId()); + _sessionProcessInfo->update(); +} + +bool Session::updateForegroundProcessInfo() +{ + bool valid = (_foregroundProcessInfo != 0); + + // has foreground process changed? + Q_ASSERT(_shellProcess); + int pid = _shellProcess->foregroundProcessGroup(); + if (pid != _foregroundPid) + { + if (valid) + delete _foregroundProcessInfo; + _foregroundProcessInfo = ProcessInfo::newInstance(pid); + _foregroundPid = pid; + valid = true; + } + + if (valid) + { + _foregroundProcessInfo->update(); + valid = _foregroundProcessInfo->isValid(); + } + + return valid; +} + +QString Session::getDynamicTitle() +{ + // update current directory from process + ProcessInfo* process = updateWorkingDirectory(); + + // format tab titles using process info + bool ok = false; + QString title; + if ( process->name(&ok) == "ssh" && ok ) + { + SSHProcessInfo sshInfo(*process); + title = sshInfo.format(tabTitleFormat(Session::RemoteTabTitle)); + } + else + title = process->format(tabTitleFormat(Session::LocalTabTitle)); + + return title; +} + +KUrl Session::getUrl() +{ + QString path; + + updateSessionProcessInfo(); + if (_sessionProcessInfo->isValid()) + { + bool ok = false; + + // check if foreground process is bookmark-able + if (isChildActive()) + { + // for remote connections, save the user and host + // bright ideas to get the directory at the other end are welcome :) + if (_foregroundProcessInfo->name(&ok) == "ssh" && ok) + { + SSHProcessInfo sshInfo(*_foregroundProcessInfo); + path = "ssh://" + sshInfo.userName() + '@' + sshInfo.host(); + } + else + { + path = _foregroundProcessInfo->currentDir(&ok); + if (!ok) + path.clear(); + } + } + else // otherwise use the current working directory of the shell process + { + path = _sessionProcessInfo->currentDir(&ok); + if (!ok) + path.clear(); + } + } + + return KUrl(path); +} + void Session::setIconName(const QString& iconName) { if ( iconName != _iconName ) @@ -984,15 +1114,51 @@ void Session::setSize(const QSize& size) emit resizeRequest(size); } -int Session::foregroundProcessId() const -{ - return _shellProcess->foregroundProcessGroup(); -} int Session::processId() const { return _shellProcess->pid(); } +bool Session::isChildActive() +{ + // foreground process info is always updated after this + return updateForegroundProcessInfo() && (processId() != _foregroundPid); +} + +QString Session::childName() +{ + QString name; + + if (updateForegroundProcessInfo()) + { + bool ok = false; + name = _foregroundProcessInfo->name(&ok); + if (!ok) + name.clear(); + } + + return name; +} + +void Session::saveSession(KConfigGroup& group) +{ + group.writePathEntry("WorkingDir", currentWorkingDirectory()); + group.writeEntry("LocalTab", tabTitleFormat(LocalTabTitle)); + group.writeEntry("RemoteTab", tabTitleFormat(RemoteTabTitle)); +} + +void Session::restoreSession(KConfigGroup& group) +{ + QString value; + + value = group.readPathEntry("WorkingDir", QString()); + if (!value.isEmpty()) setInitialWorkingDirectory(value); + value = group.readEntry("LocalTab"); + if (!value.isEmpty()) setTabTitleFormat(LocalTabTitle, value); + value = group.readEntry("RemoteTab"); + if (!value.isEmpty()) setTabTitleFormat(RemoteTabTitle, value); +} + SessionGroup::SessionGroup(QObject* parent) : QObject(parent), _masterMode(0) { @@ -1111,3 +1277,12 @@ void SessionGroup::disconnectPair(Session* master , Session* other) } #include "Session.moc" + +/* + Local Variables: + mode: c++ + c-file-style: "stroustrup" + indent-tabs-mode: nil + tab-width: 4 + End: +*/ diff --git a/src/Session.h b/src/Session.h index eb7a92b69..2af029d9f 100644 --- a/src/Session.h +++ b/src/Session.h @@ -36,12 +36,14 @@ #include "History.h" class KProcess; +class KUrl; namespace Konsole { class Emulation; class Pty; +class ProcessInfo; class TerminalDisplay; class ZModemDialog; @@ -200,6 +202,11 @@ public: */ void setInitialWorkingDirectory( const QString& dir ); + /** + * Returns the current directory of the foreground process in the session + */ + QString currentWorkingDirectory(); + /** * Sets the type of history store used by this session. * Lines of output produced by the terminal are added @@ -274,12 +281,17 @@ public: QString title(TitleRole role) const; /** Convenience method used to read the name property. Returns title(Session::NameRole). */ QString nameTitle() const { return title(Session::NameRole); } + /** Returns a title generated from tab format and process information. */ + QString getDynamicTitle(); /** Sets the name of the icon associated with this session. */ void setIconName(const QString& iconName); /** Returns the name of the icon associated with this session. */ QString iconName() const; + /** Return URL for the session. */ + KUrl getUrl(); + /** Sets the text of the icon associated with this session. */ void setIconText(const QString& iconText); /** Returns the text of the icon associated with this session. */ @@ -317,12 +329,11 @@ public: */ int processId() const; - /** - * Returns the process id of the terminal's foreground process. - * This is initially the same as processId() but can change - * as the user starts other programs inside the terminal. - */ - int foregroundProcessId() const; + /** Returns true if the user has started a program in the session. */ + bool isChildActive(); + + /** Returns the name of the current foreground process. */ + QString childName(); /** Returns the terminal session's window size in lines and columns. */ QSize size(); @@ -378,6 +389,10 @@ public: ProfileChange = 50 // this clashes with Xterm's font change command }; + // session management + void saveSession(KConfigGroup& group); + void restoreSession(KConfigGroup& group); + public slots: /** @@ -517,6 +532,10 @@ private: // checks that the binary 'program' is available and can be executed // returns the binary name if available or an empty string otherwise QString checkProgram(const QString& program) const; + ProcessInfo* getProcessInfo(); + void updateSessionProcessInfo(); + bool updateForegroundProcessInfo(); + ProcessInfo* updateWorkingDirectory(); int _uniqueIdentifier; @@ -555,6 +574,11 @@ private: int _sessionId; QString _initialWorkingDir; + QString _currentWorkingDir; + + ProcessInfo* _sessionProcessInfo; + ProcessInfo* _foregroundProcessInfo; + int _foregroundPid; // ZModem bool _zmodemBusy; @@ -653,3 +677,12 @@ private: } #endif + +/* + Local Variables: + mode: c++ + c-file-style: "stroustrup" + indent-tabs-mode: nil + tab-width: 4 + End: +*/ diff --git a/src/SessionController.cpp b/src/SessionController.cpp index ec0ac6d4e..d4ec38778 100644 --- a/src/SessionController.cpp +++ b/src/SessionController.cpp @@ -50,7 +50,6 @@ #include "IncrementalSearchBar.h" #include "ScreenWindow.h" #include "Session.h" -#include "ProcessInfo.h" #include "ProfileList.h" #include "TerminalDisplay.h" #include "SessionManager.h" @@ -204,43 +203,8 @@ void SessionController::snapshot() { Q_ASSERT( _session != 0 ); - ProcessInfo* process = 0; - ProcessInfo* snapshot = ProcessInfo::newInstance(_session->processId()); - snapshot->update(); - - // use foreground process information if available - // fallback to session process otherwise - int pid = _session->foregroundProcessId(); //snapshot->foregroundPid(&ok); - if ( pid != 0 ) - { - process = ProcessInfo::newInstance(pid); - process->update(); - } - else - process = snapshot; - - bool ok = false; - - // format tab titles using process info - QString title; - if ( process->name(&ok) == "ssh" && ok ) - { - SSHProcessInfo sshInfo(*process); - title = sshInfo.format(_session->tabTitleFormat(Session::RemoteTabTitle)); - } - else - title = process->format(_session->tabTitleFormat(Session::LocalTabTitle) ) ; - - - if ( snapshot != process ) - { - delete snapshot; - delete process; - } - else - delete snapshot; - - title = title.simplified(); + QString title = _session->getDynamicTitle(); + title = title.simplified(); // crude indicator when the session is broadcasting to others if (_copyToGroup && _copyToGroup->sessions().count() > 1) @@ -255,64 +219,12 @@ void SessionController::snapshot() QString SessionController::currentDir() const { - ProcessInfo* info = ProcessInfo::newInstance(_session->processId()); - info->update(); - - bool ok = false; - QString path = info->currentDir(&ok); - - delete info; - - if ( ok ) - return path; - else - return QString(); + return _session->currentWorkingDirectory(); } KUrl SessionController::url() const { - ProcessInfo* info = ProcessInfo::newInstance(_session->processId()); - info->update(); - - QString path; - if ( info->isValid() ) - { - bool ok = false; - - // check if foreground process is bookmark-able - int pid = _session->foregroundProcessId(); - if ( pid != 0 ) - { - ProcessInfo* foregroundInfo = ProcessInfo::newInstance(pid); - foregroundInfo->update(); - - // for remote connections, save the user and host - // bright ideas to get the directory at the other end are welcome :) - if ( foregroundInfo->name(&ok) == "ssh" && ok ) - { - SSHProcessInfo sshInfo(*foregroundInfo); - path = "ssh://" + sshInfo.userName() + '@' + sshInfo.host(); - } - else - { - path = foregroundInfo->currentDir(&ok); - - if (!ok) - path.clear(); - } - - delete foregroundInfo; - } - else // otherwise use the current working directory of the shell process - { - path = info->currentDir(&ok); - if (!ok) - path.clear(); - } - } - - delete info; - return KUrl( path ); + return _session->getUrl(); } void SessionController::rename() @@ -585,11 +497,6 @@ void SessionController::setupActions() _changeProfileMenu = new KMenu(i18n("Change Profile"),_view); collection->addAction("change-profile",_changeProfileMenu->menuAction()); connect( _changeProfileMenu , SIGNAL(aboutToShow()) , this , SLOT(prepareChangeProfileMenu()) ); - - // debugging tools - //action = collection->addAction("debug-process"); - //action->setText( "Get Foreground Process" ); - //connect( action , SIGNAL(triggered()) , this , SLOT(debugProcess()) ); } void SessionController::changeProfile(Profile::Ptr profile) { @@ -615,40 +522,6 @@ void SessionController::changeCodec(QTextCodec* codec) { _session->setCodec(codec); } -void SessionController::debugProcess() -{ - // testing facility to retrieve process information about - // currently active process in the shell - ProcessInfo* sessionProcess = ProcessInfo::newInstance(_session->processId()); - sessionProcess->update(); - - bool ok = false; - int fpid = sessionProcess->foregroundPid(&ok); - - if ( ok ) - { - ProcessInfo* fp = ProcessInfo::newInstance(fpid); - fp->update(); - - QString name = fp->name(&ok); - - if ( ok ) - { - _session->setTitle(Session::DisplayedTitleRole,name); - sessionTitleChanged(); - } - - QString currentDir = fp->currentDir(&ok); - - if ( ok ) - kDebug(1211) << currentDir; - else - kDebug(1211) << "could not read current dir of foreground process"; - - delete fp; - } - delete sessionProcess; -} void SessionController::editCurrentProfile() { @@ -692,13 +565,9 @@ void SessionController::saveSession() } bool SessionController::confirmClose() const { - if (_session->foregroundProcessId() != _session->processId()) + if (_session->isChildActive()) { - ProcessInfo* foregroundInfo = ProcessInfo::newInstance(_session->foregroundProcessId()); - foregroundInfo->update(); - bool ok = false; - QString title = foregroundInfo->name(&ok); - delete foregroundInfo; + QString title = _session->childName(); // hard coded for now. In future make it possible for the user to specify which programs // are ignored when considering whether to display a confirmation @@ -708,12 +577,12 @@ bool SessionController::confirmClose() const return true; QString question; - if (ok) - question = i18n("The program '%1' is currently running in this session." - " Are you sure you want to close it?",title); - else + if (title.isEmpty()) question = i18n("A program is currently running in this session." " Are you sure you want to close it?"); + else + question = i18n("The program '%1' is currently running in this session." + " Are you sure you want to close it?",title); int result = KMessageBox::warningYesNo(_view->window(),question,i18n("Confirm Close")); return (result == KMessageBox::Yes) ? true : false; @@ -1489,3 +1358,12 @@ QRegExp SearchHistoryTask::regExp() const } #include "SessionController.moc" + +/* + Local Variables: + mode: c++ + c-file-style: "stroustrup" + indent-tabs-mode: nil + tab-width: 4 + End: +*/ diff --git a/src/SessionController.h b/src/SessionController.h index 0672e197a..c368aebf1 100644 --- a/src/SessionController.h +++ b/src/SessionController.h @@ -209,9 +209,6 @@ private slots: void updateSearchFilter(); - // debugging slots - void debugProcess(); - private: // begins the search // text - pattern to search for @@ -439,3 +436,12 @@ private: } #endif //SESSIONCONTROLLER_H + +/* + Local Variables: + mode: c++ + c-file-style: "stroustrup" + indent-tabs-mode: nil + tab-width: 4 + End: +*/ diff --git a/src/SessionManager.cpp b/src/SessionManager.cpp index 16cb201da..b066216e9 100644 --- a/src/SessionManager.cpp +++ b/src/SessionManager.cpp @@ -730,6 +730,69 @@ QKeySequence SessionManager::shortcut(Profile::Ptr info) const return QKeySequence(); } +void SessionManager::saveSessions(KConfig* config) +{ + // The session IDs can't be restored. + // So we need to map the old ID to the future new ID. + int n = 1; + _restoreMapping.clear(); + + foreach(Session* session, _sessions) + { + QString name = QLatin1String("Session") + QString::number(n); + KConfigGroup group(config, name); + + group.writePathEntry("Profile", + _sessionProfiles.value(session)->path()); + session->saveSession(group); + _restoreMapping.insert(session, n); + n++; + } + + KConfigGroup group(config, "Number"); + group.writeEntry("NumberOfSessions", _sessions.count()); +} + +int SessionManager::getRestoreId(Session* session) +{ + return _restoreMapping.value(session); +} + +void SessionManager::restoreSessions(KConfig* config) +{ + KConfigGroup group(config, "Number"); + int sessions; + + // Any sessions saved? + if ((sessions = group.readEntry("NumberOfSessions", 0)) > 0) + { + for (int n = 1; n <= sessions; n++) + { + QString name = QLatin1String("Session") + QString::number(n); + KConfigGroup sessionGroup(config, name); + + QString profile = sessionGroup.readPathEntry("Profile", QString()); + Profile::Ptr ptr = defaultProfile(); + if (!profile.isEmpty()) ptr = loadProfile(profile); + + Session* session = createSession(ptr); + session->restoreSession(sessionGroup); + } + } +} + +Session* SessionManager::idToSession(int id) +{ + Q_ASSERT(id); + foreach(Session* session, _sessions) + if (session->sessionId() == id) + return session; + + // this should not happen + Q_ASSERT(0); + return 0; +} + K_GLOBAL_STATIC( SessionManager , theSessionManager ) SessionManager* SessionManager::instance() { @@ -833,3 +896,12 @@ QModelIndex SessionListModel::index(int row, int column, const QModelIndex& pare } #include "SessionManager.moc" + +/* + Local Variables: + mode: c++ + c-file-style: "stroustrup" + indent-tabs-mode: nil + tab-width: 4 + End: +*/ diff --git a/src/SessionManager.h b/src/SessionManager.h index 36b414c6c..e9def137d 100644 --- a/src/SessionManager.h +++ b/src/SessionManager.h @@ -243,6 +243,12 @@ public: */ static SessionManager* instance(); + // session management + void saveSessions(KConfig* config); + int getRestoreId(Session* session); + void restoreSessions(KConfig* config); + Session *idToSession(int id); + signals: /** Emitted when a profile is added to the manager. */ void profileAdded(Profile::Ptr ptr); @@ -318,6 +324,7 @@ private: QSet _types; QHash _sessionProfiles; + QHash _restoreMapping; struct ShortcutData { @@ -420,3 +427,11 @@ private: } #endif //SESSIONMANAGER_H +/* + Local Variables: + mode: c++ + c-file-style: "stroustrup" + indent-tabs-mode: nil + tab-width: 4 + End: +*/ diff --git a/src/ViewManager.cpp b/src/ViewManager.cpp index 10b6e2678..4d92cd43e 100644 --- a/src/ViewManager.cpp +++ b/src/ViewManager.cpp @@ -866,9 +866,78 @@ QList ViewManager::viewProperties() const return list; } +void ViewManager::saveSessions(KConfigGroup& group) +{ + // find all unique session restore IDs + QList ids; + QHash unique; + + // first: sessions in the active container, preserving the order + ViewContainer* container = _viewSplitter->activeContainer(); + Q_ASSERT(container); + TerminalDisplay* activeview = dynamic_cast(container->activeView()); + + QListIterator viewIter(container->views()); + int tab = 1; + while (viewIter.hasNext()) + { + TerminalDisplay *view = dynamic_cast(viewIter.next()); + Q_ASSERT(view); + Session *session = _sessionMap[view]; + ids << SessionManager::instance()->getRestoreId(session); + if (view == activeview) group.writeEntry("Active", tab); + unique.insert(session, 1); + tab++; + } + + // second: all other sessions, in random order + // we don't want to have sessions restored that are not connected + foreach(Session* session, _sessionMap) + if (!unique.contains(session)) + { + ids << SessionManager::instance()->getRestoreId(session); + unique.insert(session, 1); + } + + group.writeEntry("Sessions", ids); +} + +void ViewManager::restoreSessions(const KConfigGroup& group) +{ + QList ids = group.readEntry("Sessions", QList()); + int activeTab = group.readEntry("Active", 0); + TerminalDisplay *display = 0; + + int tab = 1; + foreach(int id, ids) + { + Session *session = SessionManager::instance()->idToSession(id); + createView(session); + if (!session->isRunning()) + session->run(); + if (tab++ == activeTab) + display = dynamic_cast(activeView()); + } + + if (display) + { + _viewSplitter->activeContainer()->setActiveView(display); + display->setFocus(Qt::OtherFocusReason); + } +} + uint qHash(QPointer display) { return qHash((TerminalDisplay*)display); } #include "ViewManager.moc" + +/* + Local Variables: + mode: c++ + c-file-style: "stroustrup" + indent-tabs-mode: nil + tab-width: 4 + End: +*/ diff --git a/src/ViewManager.h b/src/ViewManager.h index 043123f1a..67e784206 100644 --- a/src/ViewManager.h +++ b/src/ViewManager.h @@ -144,8 +144,8 @@ public: NavigationMethod navigationMethod() const; /** - * Returns the controller for the active view. activeViewChanged() is - * emitted when this changes. + * Returns the controller for the active view. activeViewChanged() is + * emitted when this changes. */ SessionController* activeViewController() const; @@ -154,6 +154,12 @@ public: */ IncrementalSearchBar* searchBar() const; + /** + * Session management + */ + void saveSessions(KConfigGroup& group); + void restoreSessions(const KConfigGroup& group); + signals: /** Emitted when the last view is removed from the view manager */ void empty(); @@ -305,3 +311,12 @@ private: } #endif + +/* + Local Variables: + mode: c++ + c-file-style: "stroustrup" + indent-tabs-mode: nil + tab-width: 4 + End: +*/ diff --git a/src/main.cpp b/src/main.cpp index 20f5a9591..1a126fc1e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -19,6 +19,7 @@ // Own #include "Application.h" +#include "MainWindow.h" #include // Unix @@ -51,6 +52,7 @@ void fillCommandLineOptions(KCmdLineOptions& options); bool useTransparency(); // returns true if transparency should be enabled bool forceNewProcess(); // returns true if new instance should use a new // process (instead of re-using an existing one) +void restoreSession(Application& app); // *** // Entry point into the Konsole terminal application. @@ -91,12 +93,14 @@ extern "C" int KDE_EXPORT kdemain(int argc,char** argv) getDisplayInformation(display,visual,colormap); Application app(display,(Qt::HANDLE)visual,(Qt::HANDLE)colormap); + restoreSession(app); return app.exec(); } else #endif { Application app; + restoreSession(app); return app.exec(); } } @@ -242,4 +246,21 @@ void getDisplayInformation(Display*& display , Visual*& visual , Colormap& color } #endif +void restoreSession(Application& app) +{ + if (app.isSessionRestored()) + { + int n = 1; + while (KMainWindow::canBeRestored(n)) + app.newMainWindow()->restore(n++); + } +} +/* + Local Variables: + mode: c++ + c-file-style: "stroustrup" + indent-tabs-mode: nil + tab-width: 4 + End: +*/