Changeset View
Changeset View
Standalone View
Standalone View
app/main.cpp
Show All 23 Lines | |||||
24 | * You should have received a copy of the GNU Library General Public * | 24 | * You should have received a copy of the GNU Library General Public * | ||
25 | * License along with this program; if not, write to the * | 25 | * License along with this program; if not, write to the * | ||
26 | * Free Software Foundation, Inc., * | 26 | * Free Software Foundation, Inc., * | ||
27 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * | 27 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * | ||
28 | ***************************************************************************/ | 28 | ***************************************************************************/ | ||
29 | 29 | | |||
30 | #include <config.h> | 30 | #include <config.h> | ||
31 | 31 | | |||
32 | #include "urlinfo.h" | ||||
33 | | ||||
32 | #include <KLocalizedString> | 34 | #include <KLocalizedString> | ||
33 | #include <Kdelibs4ConfigMigrator> | 35 | #include <Kdelibs4ConfigMigrator> | ||
34 | | ||||
35 | #include <kaboutdata.h> | 36 | #include <kaboutdata.h> | ||
36 | #include <kmessagebox.h> | 37 | #include <kmessagebox.h> | ||
37 | #include <ktexteditor/cursor.h> | 38 | #include <ktexteditor/cursor.h> | ||
38 | #include <kcrash.h> | 39 | #include <kcrash.h> | ||
39 | 40 | | |||
40 | #include <QApplication> | 41 | #include <QApplication> | ||
41 | #include <QElapsedTimer> | 42 | #include <QElapsedTimer> | ||
42 | #include <QCommandLineParser> | 43 | #include <QCommandLineParser> | ||
Show All 33 Lines | |||||
76 | #include <iostream> | 77 | #include <iostream> | ||
77 | 78 | | |||
78 | #ifdef Q_OS_MAC | 79 | #ifdef Q_OS_MAC | ||
79 | #include <CoreFoundation/CoreFoundation.h> | 80 | #include <CoreFoundation/CoreFoundation.h> | ||
80 | #endif | 81 | #endif | ||
81 | 82 | | |||
82 | using namespace KDevelop; | 83 | using namespace KDevelop; | ||
83 | 84 | | |||
85 | namespace { | ||||
86 | | ||||
87 | QString serializeOpenFilesMessage(const QVector<UrlInfo> &infos) | ||||
88 | { | ||||
89 | QByteArray message; | ||||
90 | QDataStream stream(&message, QIODevice::WriteOnly); | ||||
91 | stream << QByteArrayLiteral("open"); | ||||
92 | stream << infos; | ||||
93 | return QString::fromLatin1(message.toHex()); | ||||
94 | } | ||||
95 | | ||||
96 | void openFiles(const QVector<UrlInfo>& infos) | ||||
97 | { | ||||
98 | foreach (const UrlInfo& file, infos) { | ||||
99 | if (!ICore::self()->documentController()->openDocument(file.url, file.cursor)) { | ||||
100 | qWarning() << i18n("Could not open %1", file.url.toDisplayString(QUrl::PreferLocalFile)); | ||||
101 | } | ||||
102 | } | ||||
103 | } | ||||
104 | | ||||
105 | } | ||||
106 | | ||||
84 | class KDevelopApplication: | 107 | class KDevelopApplication: | ||
85 | #if KDEVELOP_SINGLE_APP | 108 | #if KDEVELOP_SINGLE_APP | ||
86 | public SharedTools::QtSingleApplication | 109 | public SharedTools::QtSingleApplication | ||
87 | #else | 110 | #else | ||
88 | public QApplication | 111 | public QApplication | ||
89 | #endif | 112 | #endif | ||
90 | { | 113 | { | ||
91 | public: | 114 | public: | ||
92 | explicit KDevelopApplication(int &argc, char **argv, bool GUIenabled = true) | 115 | explicit KDevelopApplication(int &argc, char **argv, bool GUIenabled = true) | ||
93 | #if KDEVELOP_SINGLE_APP | 116 | #if KDEVELOP_SINGLE_APP | ||
94 | : SharedTools::QtSingleApplication(QStringLiteral("KDevelop"), argc, argv) | 117 | : SharedTools::QtSingleApplication(QStringLiteral("KDevelop"), argc, argv) | ||
95 | #else | 118 | #else | ||
96 | : QApplication(argc, argv, GUIenabled) | 119 | : QApplication(argc, argv, GUIenabled) | ||
97 | #endif | 120 | #endif | ||
98 | { | 121 | { | ||
122 | #if KDEVELOP_SINGLE_APP | ||||
123 | Q_UNUSED(GUIenabled); | ||||
124 | #endif | ||||
125 | | ||||
99 | connect(this, &QGuiApplication::saveStateRequest, this, &KDevelopApplication::saveState); | 126 | connect(this, &QGuiApplication::saveStateRequest, this, &KDevelopApplication::saveState); | ||
100 | } | 127 | } | ||
101 | 128 | | |||
129 | #if KDEVELOP_SINGLE_APP | ||||
130 | public Q_SLOTS: | ||||
131 | void remoteArguments(const QString &message, QObject *socket) | ||||
132 | { | ||||
133 | Q_UNUSED(socket); | ||||
134 | | ||||
135 | QByteArray ba = QByteArray::fromHex(message.toLatin1()); | ||||
136 | QDataStream stream(ba); | ||||
137 | QByteArray command; | ||||
138 | stream >> command; | ||||
139 | | ||||
140 | qCDebug(APP) << "Received remote command: " << command; | ||||
141 | | ||||
142 | if (command == "open") { | ||||
143 | QVector<UrlInfo> infos; | ||||
144 | stream >> infos; | ||||
145 | openFiles(infos); | ||||
146 | } else { | ||||
147 | qCWarning(APP) << "Unknown remote command: " << command; | ||||
148 | } | ||||
149 | } | ||||
150 | | ||||
151 | void fileOpenRequested(const QString &file) | ||||
152 | { | ||||
153 | openFiles({UrlInfo(file)}); | ||||
154 | } | ||||
155 | #end | ||||
156 | | ||||
102 | private Q_SLOTS: | 157 | private Q_SLOTS: | ||
103 | void saveState( QSessionManager& sm ) { | 158 | void saveState( QSessionManager& sm ) { | ||
104 | if (KDevelop::Core::self() && KDevelop::Core::self()->sessionController()) { | 159 | if (KDevelop::Core::self() && KDevelop::Core::self()->sessionController()) { | ||
105 | QString x11SessionId = QString("%1_%2").arg(sm.sessionId()).arg(sm.sessionKey()); | 160 | QString x11SessionId = QString("%1_%2").arg(sm.sessionId()).arg(sm.sessionKey()); | ||
106 | QString kdevelopSessionId = KDevelop::Core::self()->sessionController()->activeSession()->id().toString(); | 161 | QString kdevelopSessionId = KDevelop::Core::self()->sessionController()->activeSession()->id().toString(); | ||
107 | 162 | | |||
108 | sm.setRestartCommand(QStringList() << QCoreApplication::applicationFilePath() << "-session" << x11SessionId << "-s" << kdevelopSessionId); | 163 | sm.setRestartCommand(QStringList() << QCoreApplication::applicationFilePath() << "-session" << x11SessionId << "-s" << kdevelopSessionId); | ||
109 | } | 164 | } | ||
Show All 14 Lines | 178 | for( auto it = sessions.constBegin(); it != sessions.constEnd(); ++it ) { | |||
124 | if ( ( it->name == data ) || ( it->uuid.toString() == data ) ) { | 179 | if ( ( it->name == data ) || ( it->uuid.toString() == data ) ) { | ||
125 | const KDevelop::SessionInfo& sessionRef = *it; | 180 | const KDevelop::SessionInfo& sessionRef = *it; | ||
126 | return &sessionRef; | 181 | return &sessionRef; | ||
127 | } | 182 | } | ||
128 | } | 183 | } | ||
129 | return 0; | 184 | return 0; | ||
130 | } | 185 | } | ||
131 | 186 | | |||
132 | | ||||
133 | // Represents a file to be opened, consisting of its URL and the cursor to jump to. | | |||
134 | struct UrlInfo | | |||
135 | { | | |||
136 | // Parses a file path argument and determines its line number and column and full path | | |||
137 | UrlInfo(QString path = {}) | | |||
138 | : cursor(KTextEditor::Cursor::invalid()) | | |||
139 | { | | |||
140 | if (!path.startsWith(QLatin1Char('/')) && QFileInfo(path).isRelative()) { | | |||
141 | path = QDir::currentPath() + QLatin1Char('/') + path; | | |||
142 | } | | |||
143 | url = QUrl::fromUserInput(path); | | |||
144 | | ||||
145 | if (url.isLocalFile() && !QFile::exists(path)) { | | |||
146 | // Allow opening specific lines in documents, like mydoc.cpp:10 | | |||
147 | // also supports columns, i.e. mydoc.cpp:10:42 | | |||
148 | static const QRegularExpression pattern(QStringLiteral(":(\\d+)(?::(\\d+))?$")); | | |||
149 | const auto match = pattern.match(path); | | |||
150 | if (match.isValid()) { | | |||
151 | path.chop(match.capturedLength()); | | |||
152 | int line = match.captured(1).toInt() - 1; | | |||
153 | // don't use an invalid column when the line is valid | | |||
154 | int column = qMax(0, match.captured(2).toInt() - 1); | | |||
155 | url = QUrl::fromLocalFile(path); | | |||
156 | cursor = {line, column}; | | |||
157 | } | | |||
158 | } | | |||
159 | } | | |||
160 | | ||||
161 | QUrl url; | | |||
162 | KTextEditor::Cursor cursor; | | |||
163 | }; | | |||
164 | | ||||
165 | /// Performs a DBus call to open the given @p files in the running kdev instance identified by @p pid | 187 | /// Performs a DBus call to open the given @p files in the running kdev instance identified by @p pid | ||
166 | /// Returns the exit status | 188 | /// Returns the exit status | ||
167 | static int openFilesInRunningInstance(const QVector<UrlInfo>& files, qint64 pid) | 189 | static int openFilesInRunningInstance(const QVector<UrlInfo>& files, qint64 pid) | ||
168 | { | 190 | { | ||
169 | const QString service = QString("org.kdevelop.kdevelop-%1").arg(pid); | 191 | const QString service = QString("org.kdevelop.kdevelop-%1").arg(pid); | ||
170 | QDBusInterface iface(service, "/org/kdevelop/DocumentController", "org.kdevelop.DocumentController"); | 192 | QDBusInterface iface(service, "/org/kdevelop/DocumentController", "org.kdevelop.DocumentController"); | ||
171 | 193 | | |||
172 | QStringList urls; | 194 | QStringList urls; | ||
▲ Show 20 Lines • Show All 285 Lines • ▼ Show 20 Line(s) | 464 | { | |||
458 | return 0; | 480 | return 0; | ||
459 | } | 481 | } | ||
460 | 482 | | |||
461 | // Handle extra arguments, which stand for files to open | 483 | // Handle extra arguments, which stand for files to open | ||
462 | QVector<UrlInfo> initialFiles; | 484 | QVector<UrlInfo> initialFiles; | ||
463 | foreach (const QString &file, parser.positionalArguments()) { | 485 | foreach (const QString &file, parser.positionalArguments()) { | ||
464 | initialFiles.append(UrlInfo(file)); | 486 | initialFiles.append(UrlInfo(file)); | ||
465 | } | 487 | } | ||
466 | if ( ! initialFiles.isEmpty() && ! parser.isSet("new-session") ) | 488 | | ||
489 | if (!parser.isSet("new-session")) { | ||||
490 | #if KDEVELOP_SINGLE_APP | ||||
491 | if (app.isRunning()) { | ||||
492 | bool success = app.sendMessage(serializeOpenFilesMessage(initialFiles)); | ||||
493 | if (success) { | ||||
494 | return 0; | ||||
495 | } | ||||
496 | } | ||||
497 | #endif | ||||
498 | | ||||
499 | if ( ! initialFiles.isEmpty() ) | ||||
467 | { | 500 | { | ||
468 | qint64 pid = -1; | 501 | qint64 pid = -1; | ||
469 | if (parser.isSet("open-session")) { | 502 | if (parser.isSet("open-session")) { | ||
470 | const QString session = findSessionId(parser.value("open-session")); | 503 | const QString session = findSessionId(parser.value("open-session")); | ||
471 | if (session.isEmpty()) { | 504 | if (session.isEmpty()) { | ||
472 | return 1; | 505 | return 1; | ||
473 | } else if (KDevelop::SessionController::isSessionRunning(session)) { | 506 | } else if (KDevelop::SessionController::isSessionRunning(session)) { | ||
474 | pid = findSessionPid(session); | 507 | pid = findSessionPid(session); | ||
475 | } | 508 | } | ||
476 | } else { | 509 | } else { | ||
477 | pid = getRunningSessionPid(); | 510 | pid = getRunningSessionPid(); | ||
478 | } | 511 | } | ||
479 | if ( pid > 0 ) { | 512 | if ( pid > 0 ) { | ||
480 | return openFilesInRunningInstance(initialFiles, pid); | 513 | return openFilesInRunningInstance(initialFiles, pid); | ||
481 | } | 514 | } | ||
482 | // else there are no running sessions, and the generated list of files will be opened below. | 515 | // else there are no running sessions, and the generated list of files will be opened below. | ||
483 | } | 516 | } | ||
517 | } | ||||
484 | 518 | | |||
485 | // if empty, restart kdevelop with last active session, see SessionController::defaultSessionId | 519 | // if empty, restart kdevelop with last active session, see SessionController::defaultSessionId | ||
486 | QString session; | 520 | QString session; | ||
487 | 521 | | |||
488 | uint nRunningSessions = 0; | 522 | uint nRunningSessions = 0; | ||
489 | foreach(const KDevelop::SessionInfo& si, KDevelop::SessionController::availableSessionInfos()) | 523 | foreach(const KDevelop::SessionInfo& si, KDevelop::SessionController::availableSessionInfos()) | ||
490 | if(KDevelop::SessionController::isSessionRunning(si.uuid.toString())) | 524 | if(KDevelop::SessionController::isSessionRunning(si.uuid.toString())) | ||
491 | ++nRunningSessions; | 525 | ++nRunningSessions; | ||
▲ Show 20 Lines • Show All 203 Lines • ▼ Show 20 Line(s) | 682 | if ( parser.isSet("debug") ) { | |||
695 | } | 729 | } | ||
696 | 730 | | |||
697 | type->configureLaunchFromCmdLineArguments(launch->config(), debugArgs); | 731 | type->configureLaunchFromCmdLineArguments(launch->config(), debugArgs); | ||
698 | launch->config().writeEntry("Break on Start", true); | 732 | launch->config().writeEntry("Break on Start", true); | ||
699 | core->runControllerInternal()->setDefaultLaunch(launch); | 733 | core->runControllerInternal()->setDefaultLaunch(launch); | ||
700 | 734 | | |||
701 | core->runControllerInternal()->execute("debug", launch); | 735 | core->runControllerInternal()->execute("debug", launch); | ||
702 | } else { | 736 | } else { | ||
703 | foreach ( const UrlInfo& file, initialFiles ) { | 737 | openFiles(initialFiles); | ||
704 | if(!core->documentController()->openDocument(file.url, file.cursor)) { | | |||
705 | qWarning() << i18n("Could not open %1", file.url.toDisplayString(QUrl::PreferLocalFile)); | | |||
706 | } | | |||
707 | } | | |||
708 | } | 738 | } | ||
709 | 739 | | |||
740 | #if KDEVELOP_SINGLE_APP | ||||
741 | // Set up remote arguments. | ||||
742 | QObject::connect(&app, &SharedTools::QtSingleApplication::messageReceived, | ||||
743 | &app, &KDevelopApplication::remoteArguments); | ||||
744 | | ||||
745 | QObject::connect(&app, &SharedTools::QtSingleApplication::fileOpenRequest, | ||||
746 | &app, &KDevelopApplication::fileOpenRequested); | ||||
747 | #endif | ||||
748 | | ||||
749 | | ||||
710 | #ifdef WITH_WELCOMEPAGE | 750 | #ifdef WITH_WELCOMEPAGE | ||
711 | // make it possible to disable the welcome page, useful for valgrind runs e.g. | 751 | // make it possible to disable the welcome page, useful for valgrind runs e.g. | ||
712 | if (!qEnvironmentVariableIsSet("KDEV_DISABLE_WELCOMEPAGE")) { | 752 | if (!qEnvironmentVariableIsSet("KDEV_DISABLE_WELCOMEPAGE")) { | ||
713 | trySetupWelcomePageView(); | 753 | trySetupWelcomePageView(); | ||
714 | } | 754 | } | ||
715 | #endif | 755 | #endif | ||
716 | 756 | | |||
717 | qCDebug(APP) << "Done startup" << "- took:" << timer.elapsed() << "ms"; | 757 | qCDebug(APP) << "Done startup" << "- took:" << timer.elapsed() << "ms"; | ||
718 | timer.invalidate(); | 758 | timer.invalidate(); | ||
719 | 759 | | |||
720 | return app.exec(); | 760 | return app.exec(); | ||
721 | } | 761 | } |