diff --git a/src/Application.cpp b/src/Application.cpp index 6651fe7b..6e8e1ee1 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -1,569 +1,582 @@ /* Copyright 2006-2008 by Robert Knight This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ // Own #include "Application.h" // Qt #include #include #include #include #include #include // KDE #include #include // Konsole #include "SessionManager.h" #include "ProfileManager.h" #include "MainWindow.h" #include "Session.h" #include "ShellCommand.h" #include "KonsoleSettings.h" #include "ViewManager.h" #include "SessionController.h" #include "WindowSystemInfo.h" using namespace Konsole; -Application::Application(QSharedPointer parser) : m_parser(parser) +Application::Application(QSharedPointer parser, const QStringList &customCommand) : m_parser(parser), m_customCommand(customCommand) { _backgroundInstance = 0; } void Application::populateCommandLineParser(QCommandLineParser *parser) { parser->addOption(QCommandLineOption(QStringList() << QStringLiteral("profile"), i18nc("@info:shell", "Name of profile to use for new Konsole instance"), QStringLiteral("name"))); parser->addOption(QCommandLineOption(QStringList(QStringLiteral("fallback-profile")), i18nc("@info:shell", "Use the internal FALLBACK profile"))); parser->addOption(QCommandLineOption(QStringList() << QStringLiteral("workdir"), i18nc("@info:shell", "Set the initial working directory of the new tab or" " window to 'dir'"), QStringLiteral("dir"))); parser->addOption(QCommandLineOption(QStringList() << QStringLiteral("hold") << QStringLiteral("noclose"), i18nc("@info:shell", "Do not close the initial session automatically when it" " ends."))); parser->addOption(QCommandLineOption(QStringList() << QStringLiteral("new-tab"), i18nc("@info:shell", "Create a new tab in an existing window rather than" " creating a new window"))); parser->addOption(QCommandLineOption(QStringList() << QStringLiteral("tabs-from-file"), i18nc("@info:shell", "Create tabs as specified in given tabs configuration" " file"), QStringLiteral("file"))); parser->addOption(QCommandLineOption(QStringList() << QStringLiteral("background-mode"), i18nc("@info:shell", "Start Konsole in the background and bring to the front" " when Ctrl+Shift+F12 (by default) is pressed"))); // --nofork is a compatibility alias for separate parser->addOption(QCommandLineOption(QStringList() << QStringLiteral("separate") << QStringLiteral("nofork"), i18n("Run in a separate process"))); parser->addOption(QCommandLineOption(QStringList() << QStringLiteral("show-menubar"), i18nc("@info:shell", "Show the menubar, overriding the default setting"))); parser->addOption(QCommandLineOption(QStringList() << QStringLiteral("hide-menubar"), i18nc("@info:shell", "Hide the menubar, overriding the default setting"))); parser->addOption(QCommandLineOption(QStringList() << QStringLiteral("show-tabbar"), i18nc("@info:shell", "Show the tabbar, overriding the default setting"))); parser->addOption(QCommandLineOption(QStringList() << QStringLiteral("hide-tabbar"), i18nc("@info:shell", "Hide the tabbar, overriding the default setting"))); parser->addOption(QCommandLineOption(QStringList() << QStringLiteral("fullscreen"), i18nc("@info:shell", "Start Konsole in fullscreen mode"))); parser->addOption(QCommandLineOption(QStringList() << QStringLiteral("notransparency"), i18nc("@info:shell", "Disable transparent backgrounds, even if the system" " supports them."))); parser->addOption(QCommandLineOption(QStringList() << QStringLiteral("list-profiles"), i18nc("@info:shell", "List the available profiles"))); parser->addOption(QCommandLineOption(QStringList() << QStringLiteral("list-profile-properties"), i18nc("@info:shell", "List all the profile properties names and their type" " (for use with -p)"))); parser->addOption(QCommandLineOption(QStringList() << QStringLiteral("p"), i18nc("@info:shell", "Change the value of a profile property."), QStringLiteral("property=value"))); parser->addOption(QCommandLineOption(QStringList() << QStringLiteral("e"), i18nc("@info:shell", "Command to execute. This option will catch all following" " arguments, so use it as the last option."), QStringLiteral("cmd"))); parser->addPositionalArgument(QStringLiteral("[args]"), i18nc("@info:shell", "Arguments passed to command")); // Add a no-op compatibility option to make Konsole compatible with // Debian's policy on X terminal emulators. // -T is technically meant to set a title, that is not really meaningful // for Konsole as we have multiple user-facing options controlling // the title and overriding whatever is set elsewhere. // https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=532029 // https://www.debian.org/doc/debian-policy/ch-customized-programs.html#s11.8.3 auto titleOption = QCommandLineOption(QStringList() << QStringLiteral("T"), QStringLiteral("Debian policy compatibility, not used"), QStringLiteral("value")); #if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0) titleOption.setHidden(true); #endif parser->addOption(titleOption); } +QStringList Application::getCustomCommand(QStringList &args) +{ + int i = args.indexOf("-e"); + QStringList customCommand; + if ((0 < i) && (i < (args.size() - 1))) { + // -e was specified with at least one extra argument + // if -e was specified without arguments, QCommandLineParser will deal + // with that + args.removeAt(i); + while (args.size() > i) { + customCommand << args.takeAt(i); + } + } + return customCommand; +} + Application::~Application() { SessionManager::instance()->closeAllSessions(); ProfileManager::instance()->saveSettings(); } MainWindow* Application::newMainWindow() { WindowSystemInfo::HAVE_TRANSPARENCY = !m_parser->isSet(QStringLiteral("notransparency")); MainWindow* window = new MainWindow(); connect(window, &Konsole::MainWindow::newWindowRequest, this, &Konsole::Application::createWindow); connect(window, &Konsole::MainWindow::viewDetached, this, &Konsole::Application::detachView); return window; } void Application::createWindow(Profile::Ptr profile, const QString& directory) { MainWindow* window = newMainWindow(); window->createSession(profile, directory); finalizeNewMainWindow(window); } void Application::detachView(Session* session) { MainWindow* window = newMainWindow(); window->createView(session); // When detaching a view, the size of the new window should equal the // size of the source window Session* newsession = window->viewManager()->activeViewController()->session(); newsession->setSize(session->size()); window->adjustSize(); // Since user is dragging and dropping, move dnd window to where // the user has the cursor (correct multiple monitor setups). window->move(QCursor::pos()); window->show(); } int Application::newInstance() { // handle session management // returns from processWindowArgs(args, createdNewMainWindow) // if a new window was created bool createdNewMainWindow = false; // check for arguments to print help or other information to the // terminal, quit if such an argument was found if (processHelpArgs()) return 0; // create a new window or use an existing one MainWindow* window = processWindowArgs(createdNewMainWindow); if (m_parser->isSet(QStringLiteral("tabs-from-file"))) { // create new session(s) as described in file if (!processTabsFromFileArgs(window)) { return 0; } } // select profile to use Profile::Ptr baseProfile = processProfileSelectArgs(); // process various command-line options which cause a property of the // selected profile to be changed Profile::Ptr newProfile = processProfileChangeArgs(baseProfile); // create new session Session* session = window->createSession(newProfile, QString()); if (m_parser->isSet(QStringLiteral("noclose"))) { session->setAutoClose(false); } // if the background-mode argument is supplied, start the background // session ( or bring to the front if it already exists ) if (m_parser->isSet(QStringLiteral("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. // 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 not restoring size from last time or only adding new tab, // resize window to chosen profile size (see Bug:345403) if (createdNewMainWindow){ finalizeNewMainWindow(window); } else{ window->show(); } } return 1; } /* Documentation for tab file: * * ;; is the token separator * # at the beginning of line results in line being ignored. * supported tokens are title, command and profile. * * Note that the title is static and the tab will close when the * command is complete (do not use --noclose). You can start new tabs. * * Examples: title: This is the title;; command: ssh jupiter title: Top this!;; command: top #this line is comment command: ssh earth profile: Zsh */ bool Application::processTabsFromFileArgs(MainWindow* window) { // Open tab configuration file const QString tabsFileName(m_parser->value(QStringLiteral("tabs-from-file"))); QFile tabsFile(tabsFileName); if (!tabsFile.open(QFile::ReadOnly)) { qWarning() << "ERROR: Cannot open tabs file " << tabsFileName.toLocal8Bit().data(); return false; } unsigned int sessions = 0; while (!tabsFile.atEnd()) { QString lineString(tabsFile.readLine().trimmed()); if ((lineString.isEmpty()) || (lineString[0] == '#')) continue; QHash lineTokens; QStringList lineParts = lineString.split(QStringLiteral(";;"), QString::SkipEmptyParts); for (int i = 0; i < lineParts.size(); ++i) { QString key = lineParts.at(i).section(':', 0, 0).trimmed().toLower(); QString value = lineParts.at(i).section(':', 1, -1).trimmed(); lineTokens[key] = value; } // should contain at least one of 'command' and 'profile' if (lineTokens.contains(QStringLiteral("command")) || lineTokens.contains(QStringLiteral("profile"))) { createTabFromArgs(window, lineTokens); sessions++; } else { qWarning() << "Each line should contain at least one of 'command' and 'profile'."; } } tabsFile.close(); if (sessions < 1) { qWarning() << "No valid lines found in " << tabsFileName.toLocal8Bit().data(); return false; } return true; } void Application::createTabFromArgs(MainWindow* window, const QHash& tokens) { const QString& title = tokens[QStringLiteral("title")]; const QString& command = tokens[QStringLiteral("command")]; const QString& profile = tokens[QStringLiteral("profile")]; const QString& workdir = tokens[QStringLiteral("workdir")]; Profile::Ptr baseProfile; if (!profile.isEmpty()) { baseProfile = ProfileManager::instance()->loadProfile(profile); } if (!baseProfile) { // fallback to default profile baseProfile = ProfileManager::instance()->defaultProfile(); } Profile::Ptr newProfile = Profile::Ptr(new Profile(baseProfile)); newProfile->setHidden(true); // FIXME: the method of determining whether to use newProfile does not // scale well when we support more fields in the future bool shouldUseNewProfile = false; if (!command.isEmpty()) { newProfile->setProperty(Profile::Command, command); newProfile->setProperty(Profile::Arguments, command.split(' ')); shouldUseNewProfile = true; } if (!title.isEmpty()) { newProfile->setProperty(Profile::LocalTabTitleFormat, title); newProfile->setProperty(Profile::RemoteTabTitleFormat, title); shouldUseNewProfile = true; } if (m_parser->isSet(QStringLiteral("workdir"))) { newProfile->setProperty(Profile::Directory, m_parser->value(QStringLiteral("workdir"))); shouldUseNewProfile = true; } if (!workdir.isEmpty()) { newProfile->setProperty(Profile::Directory, workdir); shouldUseNewProfile = true; } // Create the new session Profile::Ptr theProfile = shouldUseNewProfile ? newProfile : baseProfile; Session* session = window->createSession(theProfile, QString()); if (m_parser->isSet(QStringLiteral("noclose"))) { session->setAutoClose(false); } if (!window->testAttribute(Qt::WA_Resized)) { window->resize(window->sizeHint()); } // FIXME: this ugly hack here is to make the session start running, so that // its tab title is displayed as expected. // // This is another side effect of the commit fixing BKO 176902. window->show(); window->hide(); } // Creates a new Konsole window. // If --new-tab is given, use existing window. MainWindow* Application::processWindowArgs(bool &createdNewMainWindow) { MainWindow* window = 0; if (m_parser->isSet(QStringLiteral("new-tab"))) { // topLevelsWidgets() now always returns no windows BUG:373440 QListIterator iter(QApplication::topLevelWidgets()); iter.toBack(); while (iter.hasPrevious()) { window = qobject_cast(iter.previous()); if (window != 0) break; } } if (window == 0) { createdNewMainWindow = true; window = newMainWindow(); // override default menubar visibility if (m_parser->isSet(QStringLiteral("show-menubar"))) { window->setMenuBarInitialVisibility(true); } if (m_parser->isSet(QStringLiteral("hide-menubar"))) { window->setMenuBarInitialVisibility(false); } if (m_parser->isSet(QStringLiteral("fullscreen"))) { window->viewFullScreen(true); } // override default tabbbar visibility // FIXME: remove those magic number // see ViewContainer::NavigationVisibility if (m_parser->isSet(QStringLiteral("show-tabbar"))) { // always show window->setNavigationVisibility(0); } if (m_parser->isSet(QStringLiteral("hide-tabbar"))) { // never show window->setNavigationVisibility(2); } } return window; } // Loads a profile. // If --profile is given, loads profile . // If --fallback-profile is given, loads profile FALLBACK/. // Else loads the default profile. Profile::Ptr Application::processProfileSelectArgs() { Profile::Ptr defaultProfile = ProfileManager::instance()->defaultProfile(); if (m_parser->isSet(QStringLiteral("profile"))) { Profile::Ptr profile = ProfileManager::instance()->loadProfile( m_parser->value(QStringLiteral("profile"))); if (profile) return profile; } else if (m_parser->isSet(QStringLiteral("fallback-profile"))) { Profile::Ptr profile = ProfileManager::instance()->loadProfile(QStringLiteral("FALLBACK/")); if (profile) return profile; } return defaultProfile; } bool Application::processHelpArgs() { if (m_parser->isSet(QStringLiteral("list-profiles"))) { listAvailableProfiles(); return true; } else if (m_parser->isSet(QStringLiteral("list-profile-properties"))) { listProfilePropertyInfo(); return true; } return false; } void Application::listAvailableProfiles() { QStringList paths = ProfileManager::instance()->availableProfilePaths(); foreach(const QString& path, paths) { QFileInfo info(path); printf("%s\n", info.completeBaseName().toLocal8Bit().constData()); } return; } void Application::listProfilePropertyInfo() { Profile::Ptr tempProfile = ProfileManager::instance()->defaultProfile(); const QStringList names = tempProfile->propertiesInfoList(); foreach(const QString& name, names) { printf("%s\n", name.toLocal8Bit().constData()); } return; } Profile::Ptr Application::processProfileChangeArgs(Profile::Ptr baseProfile) { bool shouldUseNewProfile = false; Profile::Ptr newProfile = Profile::Ptr(new Profile(baseProfile)); newProfile->setHidden(true); // change the initial working directory if (m_parser->isSet(QStringLiteral("workdir"))) { newProfile->setProperty(Profile::Directory, m_parser->value(QStringLiteral("workdir"))); shouldUseNewProfile = true; } // temporary changes to profile options specified on the command line foreach(const QString & value , m_parser->values("p")) { ProfileCommandParser parser; QHashIterator iter(parser.parse(value)); while (iter.hasNext()) { iter.next(); newProfile->setProperty(iter.key(), iter.value()); } shouldUseNewProfile = true; } // run a custom command - if (m_parser->isSet(QStringLiteral("e"))) { - QString commandExec = m_parser->value(QStringLiteral("e")); - QStringList commandArguments; - - if (m_parser->positionalArguments().count() == 0 && - QStandardPaths::findExecutable(commandExec).isEmpty()) { + if (!m_customCommand.isEmpty()) { + // Example: konsole -e man ls + QString commandExec = m_customCommand[0]; + QStringList commandArguments(m_customCommand); + if ((m_customCommand.size() == 1) && + (QStandardPaths::findExecutable(commandExec).isEmpty())) { // Example: konsole -e "man ls" - ShellCommand shellCommand(m_parser->value(QStringLiteral("e"))); + ShellCommand shellCommand(commandExec); commandExec = shellCommand.command(); commandArguments = shellCommand.arguments(); - } else { - // Example: konsole -e man ls - commandArguments << commandExec; - for ( int i = 0 ; i < m_parser->positionalArguments().count() ; i++ ) - commandArguments << m_parser->positionalArguments().at(i); } if (commandExec.startsWith(QLatin1String("./"))) commandExec = QDir::currentPath() + commandExec.mid(1); newProfile->setProperty(Profile::Command, commandExec); newProfile->setProperty(Profile::Arguments, commandArguments); shouldUseNewProfile = true; } if (shouldUseNewProfile) { return newProfile; } else { return baseProfile; } } void Application::startBackgroundMode(MainWindow* window) { if (_backgroundInstance) { return; } /* FIXME: This doesn't work ATM - leave in here so I dont' forget about it KActionCollection* collection = window->actionCollection(); QAction * action = collection->addAction("toggle-background-window"); action->setObjectName(QLatin1String("Konsole Background Mode")); action->setText(i18n("Toggle Background Window")); action->setGlobalShortcut(QKeySequence(Konsole::ACCEL + Qt::SHIFT + Qt::Key_F12))); connect(action, &QAction::triggered, this, &Application::toggleBackgroundInstance); */ _backgroundInstance = window; } void Application::toggleBackgroundInstance() { Q_ASSERT(_backgroundInstance); if (!_backgroundInstance->isVisible()) { _backgroundInstance->show(); // ensure that the active terminal display has the focus. Without // this, an odd problem occurred where the focus widget would change // each time the background instance was shown _backgroundInstance->setFocus(); } else { _backgroundInstance->hide(); } } void Application::slotActivateRequested (QStringList args, const QString & /*workingDir*/) { // QCommandLineParser expects the first argument to be the executable name // In the current version it just strips it away args.prepend(qApp->applicationFilePath()); + m_customCommand = getCustomCommand(args); + // We can't re-use QCommandLineParser instances, it preserves earlier parsed values QCommandLineParser *parser = new QCommandLineParser; populateCommandLineParser(parser); parser->parse(args); m_parser.reset(parser); newInstance(); } void Application::finalizeNewMainWindow(MainWindow* window) { if (!KonsoleSettings::saveGeometryOnExit()) window->resize(window->sizeHint()); window->show(); } diff --git a/src/Application.h b/src/Application.h index 8987d789..8ec7ab6a 100644 --- a/src/Application.h +++ b/src/Application.h @@ -1,94 +1,96 @@ /* Copyright 2007-2008 by Robert Knight This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef APPLICATION_H #define APPLICATION_H // Qt #include #include // Konsole #include "Profile.h" namespace Konsole { class MainWindow; class Session; /** * The Konsole Application. * * The application consists of one or more main windows and a set of * factories to create new sessions and views. * * To create a new main window with a default terminal session, call * the newInstance(). Empty main windows can be created using newMainWindow(). * * The factory used to create new terminal sessions can be retrieved using * the sessionManager() accessor. */ class Application : public QObject { Q_OBJECT public: /** Constructs a new Konsole application. */ - explicit Application(QSharedPointer parser); + explicit Application(QSharedPointer parser, const QStringList &customCommand); static void populateCommandLineParser(QCommandLineParser *parser); + static QStringList getCustomCommand(QStringList &args); ~Application(); /** Creates a new main window and opens a default terminal session */ int newInstance(); /** * Creates a new, empty main window and connects to its newSessionRequest() * and newWindowRequest() signals to trigger creation of new sessions or * windows when then they are emitted. */ MainWindow* newMainWindow(); private slots: void createWindow(Profile::Ptr profile , const QString& directory); void detachView(Session* session); void toggleBackgroundInstance(); public slots: void slotActivateRequested (QStringList args, const QString &workingDir); private: void listAvailableProfiles(); void listProfilePropertyInfo(); void startBackgroundMode(MainWindow* window); bool processHelpArgs(); MainWindow* processWindowArgs(bool &createdNewMainWindow); Profile::Ptr processProfileSelectArgs(); Profile::Ptr processProfileChangeArgs(Profile::Ptr baseProfile); bool processTabsFromFileArgs(MainWindow* window); void createTabFromArgs(MainWindow* window, const QHash&); void finalizeNewMainWindow(MainWindow* window); MainWindow* _backgroundInstance; QSharedPointer m_parser; + QStringList m_customCommand; }; } #endif // APPLICATION_H diff --git a/src/main.cpp b/src/main.cpp index f4bb5af3..fb53560e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,344 +1,348 @@ /* Copyright 2006-2008 by Robert Knight This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ // Own #include "Application.h" #include "MainWindow.h" #include "config-konsole.h" #include "KonsoleSettings.h" // OS specific #include #include #include #include // KDE #include #include #include #include #include #include using Konsole::Application; // fill the KAboutData structure with information about contributors to Konsole. void fillAboutData(KAboutData& aboutData); // check and report whether this konsole instance should use a new konsole // process, or re-use an existing konsole process. bool shouldUseNewProcess(int argc, char *argv[]); // restore sessions saved by KDE. void restoreSession(Application& app); // Workaround for a bug in KDBusService: https://bugs.kde.org/show_bug.cgi?id=355545 // It calls exit(), but the program can't exit before the QApplication is deleted: // https://bugreports.qt.io/browse/QTBUG-48709 static bool needToDeleteQApplication = false; void deleteQApplication() { if (needToDeleteQApplication) { delete qApp; } } // *** // Entry point into the Konsole terminal application. // *** extern "C" int Q_DECL_EXPORT kdemain(int argc, char* argv[]) { // Check if any of the arguments makes it impossible to re-use an existing process. // We need to do this manually and before creating a QApplication, because // QApplication takes/removes the Qt specific arguments that are incompatible. KDBusService::StartupOption startupOption = KDBusService::Unique; if (shouldUseNewProcess(argc, argv)) { startupOption = KDBusService::Multiple; } else { needToDeleteQApplication = true; } QApplication *app = new QApplication(argc, argv); // enable high dpi support app->setAttribute(Qt::AA_UseHighDpiPixmaps, true); #if defined(Q_OS_OSX) // this ensures that Ctrl and Meta are not swapped, so CTRL-C and friends // will work correctly in the terminal app->setAttribute(Qt::AA_MacDontSwapCtrlAndMeta); // KDE's menuBar()->isTopLevel() hasn't worked in a while. // For now, put menus inside Konsole window; this also make // the keyboard shortcut to show menus look reasonable. app->setAttribute(Qt::AA_DontUseNativeMenuBar); #endif KLocalizedString::setApplicationDomain("konsole"); KAboutData about(QStringLiteral("konsole"), i18nc("@title", "Konsole"), QStringLiteral(KONSOLE_VERSION), i18nc("@title", "Terminal emulator"), KAboutLicense::GPL_V2, i18n("(c) 1997-2015, The Konsole Developers"), QStringLiteral(), QStringLiteral("https://konsole.kde.org/")); fillAboutData(about); KAboutData::setApplicationData(about); KCrash::initialize(); QSharedPointer parser(new QCommandLineParser); parser->setApplicationDescription(about.shortDescription()); parser->addHelpOption(); parser->addVersionOption(); about.setupCommandLine(parser.data()); + + QStringList args = QStringList(app->arguments()); + QStringList customCommand = Application::getCustomCommand(args); + Application::populateCommandLineParser(parser.data()); - parser->process(*app); + parser->process(args); about.processCommandLine(parser.data()); // Enable user to force multiple instances if (!Konsole::KonsoleSettings::useSingleInstance()) { startupOption = KDBusService::Multiple; } atexit(deleteQApplication); // Ensure that we only launch a new instance if we need to // If there is already an instance running, we will quit here KDBusService dbusService(startupOption | KDBusService::NoExitOnFailure); needToDeleteQApplication = false; Kdelibs4ConfigMigrator migrate(QStringLiteral("konsole")); migrate.setConfigFiles(QStringList() << QStringLiteral("konsolerc") << QStringLiteral("konsole.notifyrc")); migrate.setUiFiles(QStringList() << QStringLiteral("sessionui.rc") << QStringLiteral("partui.rc") << QStringLiteral("konsoleui.rc")); if (migrate.migrate()) { Kdelibs4Migration dataMigrator; const QString sourceBasePath = dataMigrator.saveLocation("data", QStringLiteral("konsole")); const QString targetBasePath = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QStringLiteral("/konsole/"); QString targetFilePath; QDir sourceDir(sourceBasePath); QDir targetDir(targetBasePath); if(sourceDir.exists()) { if(!targetDir.exists()) { QDir().mkpath(targetBasePath); } QStringList fileNames = sourceDir.entryList(QDir::Files | QDir::NoDotAndDotDot | QDir::NoSymLinks); foreach (const QString &fileName, fileNames) { targetFilePath = targetBasePath + fileName; if(!QFile::exists(targetFilePath)) { QFile::copy(sourceBasePath + fileName, targetFilePath); } } } } // If we reach this location, there was no existing copy of Konsole // running, so create a new instance. - Application konsoleApp(parser); + Application konsoleApp(parser, customCommand); // The activateRequested() signal is emitted when a second instance // of Konsole is started. QObject::connect(&dbusService, &KDBusService::activateRequested, &konsoleApp, &Application::slotActivateRequested); if (app->isSessionRestored()) { restoreSession(konsoleApp); } else if (!konsoleApp.newInstance()) { // Do not finish starting Konsole // 1. An argument was given to just printed info // 2. An invalid situation ocurred delete app; return 0; } // Since we've allocated the QApplication on the heap for the KDBusService workaround, // we need to delete it manually before returning from main(). int ret = app->exec(); delete app; return ret; } bool shouldUseNewProcess(int argc, char *argv[]) { // The "unique process" model of konsole is incompatible with some or all // Qt/KDE options. When those incompatible options are given, konsole must // use new process // // TODO: make sure the existing list is OK and add more incompatible options. // We need to manually parse the arguments because QApplication removes the // Qt specific arguments (like --reverse) QStringList arguments; for (int i=0; i < argc; i++) { arguments.append(QString::fromLocal8Bit(argv[i])); } // take Qt options into consideration QStringList qtProblematicOptions; qtProblematicOptions << QStringLiteral("--session") << QStringLiteral("--name") << QStringLiteral("--reverse") << QStringLiteral("--stylesheet") << QStringLiteral("--graphicssystem"); #if HAVE_X11 qtProblematicOptions << QStringLiteral("--display") << QStringLiteral("--visual"); #endif foreach(const QString& option, qtProblematicOptions) { if (arguments.contains(option)) { return true; } } // take KDE options into consideration QStringList kdeProblematicOptions; kdeProblematicOptions << QStringLiteral("--config") << QStringLiteral("--style"); #if HAVE_X11 kdeProblematicOptions << QStringLiteral("--waitforwm"); #endif foreach(const QString& option, kdeProblematicOptions) { if (arguments.contains(option)) { return true; } } // if users have explictly requested starting a new process // Support --nofork to retain argument compatibility with older // versions. if (arguments.contains(QStringLiteral("--separate")) || arguments.contains(QStringLiteral("--nofork"))) { return true; } // the only way to create new tab is to reuse existing Konsole process. if (arguments.contains(QStringLiteral("--new-tab"))) { return false; } // when starting Konsole from a terminal, a new process must be used // so that the current environment is propagated into the shells of the new // Konsole and any debug output or warnings from Konsole are written to // the current terminal bool hasControllingTTY = false; const int fd = QT_OPEN("/dev/tty", O_RDONLY); if (fd != -1) { hasControllingTTY = true; close(fd); } return hasControllingTTY; } void fillAboutData(KAboutData& aboutData) { aboutData.setProgramIconName(QStringLiteral("utilities-terminal")); aboutData.setOrganizationDomain("kde.org"); aboutData.addAuthor(i18nc("@info:credit", "Kurt Hindenburg"), i18nc("@info:credit", "General maintainer, bug fixes and general" " improvements"), QStringLiteral("kurt.hindenburg@gmail.com")); aboutData.addAuthor(i18nc("@info:credit", "Robert Knight"), i18nc("@info:credit", "Previous maintainer, ported to KDE4"), QStringLiteral("robertknight@gmail.com")); aboutData.addAuthor(i18nc("@info:credit", "Lars Doelle"), i18nc("@info:credit", "Original author"), QStringLiteral("lars.doelle@on-line.de")); aboutData.addCredit(i18nc("@info:credit", "Jekyll Wu"), i18nc("@info:credit", "Bug fixes and general improvements"), QStringLiteral("adaptee@gmail.com")); aboutData.addCredit(i18nc("@info:credit", "Waldo Bastian"), i18nc("@info:credit", "Bug fixes and general improvements"), QStringLiteral("bastian@kde.org")); aboutData.addCredit(i18nc("@info:credit", "Stephan Binner"), i18nc("@info:credit", "Bug fixes and general improvements"), QStringLiteral("binner@kde.org")); aboutData.addCredit(i18nc("@info:credit", "Thomas Dreibholz"), i18nc("@info:credit", "General improvements"), QStringLiteral("dreibh@iem.uni-due.de")); aboutData.addCredit(i18nc("@info:credit", "Chris Machemer"), i18nc("@info:credit", "Bug fixes"), QStringLiteral("machey@ceinetworks.com")); aboutData.addCredit(i18nc("@info:credit", "Francesco Cecconi"), i18nc("@info:credit", "Bug fixes"), QStringLiteral("francesco.cecconi@gmail.com")); aboutData.addCredit(i18nc("@info:credit", "Stephan Kulow"), i18nc("@info:credit", "Solaris support and history"), QStringLiteral("coolo@kde.org")); aboutData.addCredit(i18nc("@info:credit", "Alexander Neundorf"), i18nc("@info:credit", "Bug fixes and improved startup performance"), QStringLiteral("neundorf@kde.org")); aboutData.addCredit(i18nc("@info:credit", "Peter Silva"), i18nc("@info:credit", "Marking improvements"), QStringLiteral("Peter.A.Silva@gmail.com")); aboutData.addCredit(i18nc("@info:credit", "Lotzi Boloni"), i18nc("@info:credit", "Embedded Konsole\n" "Toolbar and session names"), QStringLiteral("boloni@cs.purdue.edu")); aboutData.addCredit(i18nc("@info:credit", "David Faure"), i18nc("@info:credit", "Embedded Konsole\n" "General improvements"), QStringLiteral("faure@kde.org")); aboutData.addCredit(i18nc("@info:credit", "Antonio Larrosa"), i18nc("@info:credit", "Visual effects"), QStringLiteral("larrosa@kde.org")); aboutData.addCredit(i18nc("@info:credit", "Matthias Ettrich"), i18nc("@info:credit", "Code from the kvt project\n" "General improvements"), QStringLiteral("ettrich@kde.org")); aboutData.addCredit(i18nc("@info:credit", "Warwick Allison"), i18nc("@info:credit", "Schema and text selection improvements"), QStringLiteral("warwick@troll.no")); aboutData.addCredit(i18nc("@info:credit", "Dan Pilone"), i18nc("@info:credit", "SGI port"), QStringLiteral("pilone@slac.com")); aboutData.addCredit(i18nc("@info:credit", "Kevin Street"), i18nc("@info:credit", "FreeBSD port"), QStringLiteral("street@iname.com")); aboutData.addCredit(i18nc("@info:credit", "Sven Fischer"), i18nc("@info:credit", "Bug fixes"), QStringLiteral("herpes@kawo2.renditionwth-aachen.de")); aboutData.addCredit(i18nc("@info:credit", "Dale M. Flaven"), i18nc("@info:credit", "Bug fixes"), QStringLiteral("dflaven@netport.com")); aboutData.addCredit(i18nc("@info:credit", "Martin Jones"), i18nc("@info:credit", "Bug fixes"), QStringLiteral("mjones@powerup.com.au")); aboutData.addCredit(i18nc("@info:credit", "Lars Knoll"), i18nc("@info:credit", "Bug fixes"), QStringLiteral("knoll@mpi-hd.mpg.de")); aboutData.addCredit(i18nc("@info:credit", "Thanks to many others.\n")); } void restoreSession(Application& app) { int n = 1; while (KMainWindow::canBeRestored(n)) app.newMainWindow()->restore(n++); }