diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7a910b49..6a2d0544 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,225 +1,225 @@ # cmake-options : -DCMAKE_DISABLE_FIND_PACKAGE_LibKonq=TRUE or FALSE; default is FALSE add_definitions(-DTRANSLATION_DOMAIN=\"konsole\") ### Handle DragonFlyBSD here instead of using __DragonFly__ IF(${CMAKE_SYSTEM_NAME} MATCHES "DragonFly") set(HAVE_OS_DRAGONFLYBSD 1) else() set(HAVE_OS_DRAGONFLYBSD 0) endif() IF(NOT (${KF5_VERSION} VERSION_LESS "5.60.0")) set(USE_TERMINALINTERFACEV2 1) endif() include(CheckIncludeFiles) include(ECMAddAppIcon) configure_file(config-konsole.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-konsole.h) ### Tests if(BUILD_TESTING) find_package(Qt5Test ${QT_MIN_VERSION} CONFIG REQUIRED) add_subdirectory(autotests) add_subdirectory(tests) endif() ### Security concerns about sendText and runCommand dbus methods being public option(REMOVE_SENDTEXT_RUNCOMMAND_DBUS_METHODS "Konsole: remove sendText and runCommand dbus methods" OFF) ### Development tools option(KONSOLE_BUILD_UNI2CHARACTERWIDTH "Konsole: build uni2characterwidth executable" OFF) ### Konsole source files shared between embedded terminal and main application # qdbuscpp2xml -m Session.h -o org.kde.konsole.Session.xml # qdbuscpp2xml -M -s ViewManager.h -o org.kde.konsole.Konsole.xml # Generate dbus .xml files; do not store .xml in source folder qt5_generate_dbus_interface(Session.h org.kde.konsole.Session.xml OPTIONS -m) qt5_generate_dbus_interface(ViewManager.h org.kde.konsole.Window.xml OPTIONS -m) qt5_add_dbus_adaptor(sessionadaptors_SRCS ${CMAKE_CURRENT_BINARY_DIR}/org.kde.konsole.Session.xml Session.h Konsole::Session) qt5_add_dbus_adaptor(windowadaptors_SRCS ${CMAKE_CURRENT_BINARY_DIR}/org.kde.konsole.Window.xml ViewManager.h Konsole::ViewManager) set(konsoleprivate_SRCS ${sessionadaptors_SRCS} ${windowadaptors_SRCS} hsluv.c BookmarkHandler.cpp BookmarkMenu.cpp ColorScheme.cpp ColorSchemeManager.cpp ColorSchemeEditor.cpp CopyInputDialog.cpp EditProfileDialog.cpp FontDialog.cpp Emulation.cpp DetachableTabBar.cpp Filter.cpp History.cpp HistorySizeDialog.cpp HistorySizeWidget.cpp IncrementalSearchBar.cpp KeyBindingEditor.cpp KeyboardTranslator.cpp KeyboardTranslatorManager.cpp ProcessInfo.cpp Profile.cpp ProfileList.cpp ProfileReader.cpp ProfileWriter.cpp ProfileManager.cpp Pty.cpp RenameTabDialog.cpp RenameTabWidget.cpp SaveHistoryTask.cpp SearchHistoryTask.cpp Screen.cpp ScreenWindow.cpp ScrollState.cpp Session.cpp SessionController.cpp SessionManager.cpp SessionListModel.cpp SessionTask.cpp ShellCommand.cpp TabTitleFormatButton.cpp TerminalCharacterDecoder.cpp ExtendedCharTable.cpp TerminalDisplay.cpp TerminalDisplayAccessible.cpp TerminalHeaderBar.cpp LineBlockCharacters.cpp ViewContainer.cpp ViewManager.cpp ViewProperties.cpp ViewSplitter.cpp Vt102Emulation.cpp ZModemDialog.cpp PrintOptions.cpp WindowSystemInfo.cpp CharacterWidth.cpp ${CMAKE_CURRENT_BINARY_DIR}/org.kde.konsole.Window.xml ${CMAKE_CURRENT_BINARY_DIR}/org.kde.konsole.Session.xml) ecm_qt_declare_logging_category(konsoleprivate_SRCS HEADER konsoledebug.h IDENTIFIER KonsoleDebug CATEGORY_NAME org.kde.konsole) kconfig_add_kcfg_files(konsoleprivate_SRCS settings/KonsoleSettings.kcfgc) set(konsole_LIBS KF5::XmlGui Qt5::PrintSupport Qt5::Xml KF5::Notifications KF5::WindowSystem KF5::TextWidgets KF5::GuiAddons KF5::IconThemes KF5::Bookmarks KF5::I18n KF5::Pty KF5::KIOWidgets KF5::DBusAddons KF5::GlobalAccel KF5::NewStuff ) if(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD") #kinfo_getfile() is in libutil list(APPEND konsole_LIBS util) endif() ### Konsole Application ki18n_wrap_ui(konsoleprivate_SRCS ColorSchemeEditor.ui CopyInputDialog.ui EditProfileGeneralPage.ui EditProfileTabsPage.ui EditProfileAppearancePage.ui EditProfileScrollingPage.ui EditProfileKeyboardPage.ui EditProfileMousePage.ui EditProfileAdvancedPage.ui KeyBindingEditor.ui RenameTabDialog.ui RenameTabWidget.ui HistorySizeDialog.ui HistorySizeWidget.ui PrintOptions.ui settings/TemporaryFilesSettings.ui settings/GeneralSettings.ui settings/PartInfo.ui settings/ProfileSettings.ui settings/TabBarSettings.ui) # add the resource files for the ui files qt5_add_resources( konsoleprivate_SRCS ../desktop/konsole.qrc) add_library(konsoleprivate ${konsoleprivate_SRCS}) generate_export_header(konsoleprivate BASE_NAME konsoleprivate) target_link_libraries(konsoleprivate PUBLIC ${konsole_LIBS}) set_target_properties(konsoleprivate PROPERTIES VERSION ${KONSOLEPRIVATE_VERSION_STRING} SOVERSION ${KONSOLEPRIVATE_SOVERSION} ) install(TARGETS konsoleprivate ${KDE_INSTALL_TARGETS_DEFAULT_ARGS} LIBRARY NAMELINK_SKIP) set(konsole_KDEINIT_SRCS Application.cpp MainWindow.cpp main.cpp settings/ConfigurationDialog.cpp settings/TemporaryFilesSettings.cpp settings/GeneralSettings.cpp settings/ProfileSettings.cpp settings/TabBarSettings.cpp) # Sets the icon on Windows and OSX file(GLOB ICONS_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/../data/icons/*.png") ecm_add_app_icon(kdeinit_konsole ICONS ${ICONS_SRCS}) kf5_add_kdeinit_executable(konsole ${konsole_KDEINIT_SRCS}) target_link_libraries(kdeinit_konsole konsoleprivate KF5::XmlGui KF5::WindowSystem KF5::Bookmarks KF5::I18n KF5::KIOWidgets KF5::NotifyConfig KF5::Crash ) if(APPLE) set_target_properties(konsole PROPERTIES MACOSX_BUNDLE_GUI_IDENTIFIER "org.kde.konsole" MACOSX_BUNDLE_BUNDLE_NAME "Konsole" MACOSX_BUNDLE_DISPLAY_NAME "Konsole" MACOSX_BUNDLE_INFO_STRING "Konsole, the KDE terminal emulator" MACOSX_BUNDLE_LONG_VERSION_STRING "Konsole ${KDE_APPLICATIONS_VERSION}" MACOSX_BUNDLE_SHORT_VERSION_STRING "${KDE_APPLICATIONS_VERSION_MAJOR}.${KDE_APPLICATIONS_VERSION_MINOR}" MACOSX_BUNDLE_BUNDLE_VERSION "${KDE_APPLICATIONS_VERSION}" - MACOSX_BUNDLE_COPYRIGHT "1997-2016 The Konsole Developers") + MACOSX_BUNDLE_COPYRIGHT "1997-2020 The Konsole Developers") endif() install(TARGETS kdeinit_konsole konsole ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) ### Embedded Konsole KPart set(konsolepart_PART_SRCS Part.cpp settings/PartInfo.cpp settings/ProfileSettings.cpp) add_library(konsolepart MODULE ${konsolepart_PART_SRCS}) generate_export_header(konsolepart BASE_NAME konsole) kcoreaddons_desktop_to_json(konsolepart ../desktop/konsolepart.desktop) set_target_properties(konsolepart PROPERTIES DEFINE_SYMBOL KONSOLE_PART) target_link_libraries(konsolepart KF5::Parts KF5::XmlGui konsoleprivate) install(TARGETS konsolepart DESTINATION ${KDE_INSTALL_PLUGINDIR}) diff --git a/src/main.cpp b/src/main.cpp index 06f3ce49..5373cce4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,404 +1,404 @@ /* 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" #include "ViewManager.h" #include "ViewContainer.h" // OS specific #include #include #include #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; } } // This override resolves following problem: since some qt version if // XDG_CURRENT_DESKTOP ≠ kde, then pressing and immediately releasing Alt // key makes focus get stuck in QMenu. // Upstream report: https://bugreports.qt.io/browse/QTBUG-77355 class MenuStyle : public QProxyStyle { public: int styleHint(const StyleHint stylehint, const QStyleOption *opt, const QWidget *widget, QStyleHintReturn *returnData) const override { return (stylehint == QStyle::SH_MenuBar_AltKeyNavigation) ? 0 : QProxyStyle::styleHint(stylehint, opt, widget, returnData); } }; // *** // Entry point into the Konsole terminal application. // *** extern "C" int Q_DECL_EXPORT kdemain(int argc, char *argv[]) { // enable high dpi support QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps, true); QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling, true); // 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; } #if defined(Q_OS_LINUX) && (QT_VERSION < QT_VERSION_CHECK(5, 11, 2)) // Workaround for https://bugreports.qt.io/browse/QTBUG-48344 // See also https://bugs.kde.org/show_bug.cgi?id=230184 // The Qt glib event loop doesn't let timers deliver events if there are a // lot of other events. const QByteArray qtUseGLibOld = qgetenv("QT_NO_GLIB"); qputenv("QT_NO_GLIB", "1"); #endif // Allocate QApplication on the heap for the KDBusService workaround auto app = std::unique_ptr(new QApplication(argc, argv)); app->setStyle(new MenuStyle()); #if defined(Q_OS_LINUX) && (QT_VERSION < QT_VERSION_CHECK(5, 11, 2)) if (qtUseGLibOld.isNull()) { qunsetenv("QT_NO_GLIB"); } else { qputenv("QT_NO_GLIB", qtUseGLibOld); } #endif #if defined(Q_OS_MACOS) // 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 app->setWindowIcon(QIcon::fromTheme(QStringLiteral("utilities-terminal"))); KLocalizedString::setApplicationDomain("konsole"); KAboutData about(QStringLiteral("konsole"), i18nc("@title", "Konsole"), QStringLiteral(KONSOLE_VERSION), i18nc("@title", "Terminal emulator"), KAboutLicense::GPL_V2, - i18nc("@info:credit", "(c) 1997-2019, The Konsole Developers"), + i18nc("@info:credit", "(c) 1997-2020, The Konsole Developers"), QString(), 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 = app->arguments(); QStringList customCommand = Application::getCustomCommand(args); Application::populateCommandLineParser(parser.data()); parser->process(args); about.processCommandLine(parser.data()); // Enable user to force multiple instances, unless a new tab is requested if (!Konsole::KonsoleSettings::useSingleInstance() && !parser->isSet(QStringLiteral("new-tab"))) { 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, 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 { // Do not finish starting Konsole due to: // 1. An argument was given to just printed info // 2. An invalid situation occurred const bool continueStarting = (konsoleApp.newInstance() != 0); if (!continueStarting) { return 0; } } int ret = app->exec(); 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; arguments.reserve(argc); 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(QLatin1String("--separate")) || arguments.contains(QLatin1String("--nofork"))) { return true; } // the only way to create new tab is to reuse existing Konsole process. if (arguments.contains(QLatin1String("--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.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)) { auto mainWindow = app.newMainWindow(); mainWindow->restore(n++); mainWindow->viewManager()->toggleActionsBasedOnState(); mainWindow->show(); // TODO: HACK without the code below the sessions would be `uninitialized` // and the tabs wouldn't display the correct information. auto tabbedContainer = qobject_cast(mainWindow->centralWidget()); for(int i = 0; i < tabbedContainer->count(); i++) { tabbedContainer->setCurrentIndex(i); } } }