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 | qWarning() << "FILE" << file.url << file.cursor; | ||||
100 | if (!ICore::self()->documentController()->openDocument(file.url, file.cursor)) { | ||||
101 | qWarning() << i18n("Could not open %1", file.url.toDisplayString(QUrl::PreferLocalFile)); | ||||
102 | } | ||||
103 | } | ||||
104 | } | ||||
105 | | ||||
106 | } | ||||
107 | | ||||
84 | class KDevelopApplication: | 108 | class KDevelopApplication: | ||
85 | #if KDEVELOP_SINGLE_APP | 109 | #if KDEVELOP_SINGLE_APP | ||
86 | public SharedTools::QtSingleApplication | 110 | public SharedTools::QtSingleApplication | ||
87 | #else | 111 | #else | ||
88 | public QApplication | 112 | public QApplication | ||
89 | #endif | 113 | #endif | ||
90 | { | 114 | { | ||
91 | public: | 115 | public: | ||
92 | explicit KDevelopApplication(int &argc, char **argv, bool GUIenabled = true) | 116 | explicit KDevelopApplication(int &argc, char **argv, bool GUIenabled = true) | ||
93 | #if KDEVELOP_SINGLE_APP | 117 | #if KDEVELOP_SINGLE_APP | ||
94 | : SharedTools::QtSingleApplication(QStringLiteral("KDevelop"), argc, argv) | 118 | : SharedTools::QtSingleApplication(QStringLiteral("KDevelop"), argc, argv) | ||
95 | #else | 119 | #else | ||
96 | : QApplication(argc, argv, GUIenabled) | 120 | : QApplication(argc, argv, GUIenabled) | ||
97 | #endif | 121 | #endif | ||
98 | { | 122 | { | ||
123 | #if KDEVELOP_SINGLE_APP | ||||
124 | Q_UNUSED(GUIenabled); | ||||
125 | #endif | ||||
126 | | ||||
99 | connect(this, &QGuiApplication::saveStateRequest, this, &KDevelopApplication::saveState); | 127 | connect(this, &QGuiApplication::saveStateRequest, this, &KDevelopApplication::saveState); | ||
100 | } | 128 | } | ||
101 | 129 | | |||
130 | #if KDEVELOP_SINGLE_APP | ||||
131 | public Q_SLOTS: | ||||
132 | void remoteArguments(const QString &message, QObject *socket) | ||||
133 | { | ||||
134 | Q_UNUSED(socket); | ||||
135 | | ||||
136 | QByteArray ba = QByteArray::fromHex(message.toLatin1()); | ||||
137 | QDataStream stream(ba); | ||||
138 | QByteArray command; | ||||
139 | stream >> command; | ||||
140 | | ||||
141 | qCDebug(APP) << "Received remote command: " << command; | ||||
142 | | ||||
143 | if (command == "open") { | ||||
144 | QVector<UrlInfo> infos; | ||||
145 | stream >> infos; | ||||
146 | openFiles(infos); | ||||
147 | } else { | ||||
148 | qCWarning(APP) << "Unknown remote command: " << command; | ||||
149 | } | ||||
150 | } | ||||
151 | | ||||
152 | void fileOpenRequested(const QString &file) | ||||
153 | { | ||||
154 | openFiles({UrlInfo(file)}); | ||||
155 | } | ||||
156 | #end | ||||
157 | | ||||
102 | private Q_SLOTS: | 158 | private Q_SLOTS: | ||
103 | void saveState( QSessionManager& sm ) { | 159 | void saveState( QSessionManager& sm ) { | ||
104 | if (KDevelop::Core::self() && KDevelop::Core::self()->sessionController()) { | 160 | if (KDevelop::Core::self() && KDevelop::Core::self()->sessionController()) { | ||
105 | QString x11SessionId = QString("%1_%2").arg(sm.sessionId()).arg(sm.sessionKey()); | 161 | QString x11SessionId = QString("%1_%2").arg(sm.sessionId()).arg(sm.sessionKey()); | ||
106 | QString kdevelopSessionId = KDevelop::Core::self()->sessionController()->activeSession()->id().toString(); | 162 | QString kdevelopSessionId = KDevelop::Core::self()->sessionController()->activeSession()->id().toString(); | ||
107 | 163 | | |||
108 | sm.setRestartCommand(QStringList() << QCoreApplication::applicationFilePath() << "-session" << x11SessionId << "-s" << kdevelopSessionId); | 164 | sm.setRestartCommand(QStringList() << QCoreApplication::applicationFilePath() << "-session" << x11SessionId << "-s" << kdevelopSessionId); | ||
109 | } | 165 | } | ||
Show All 14 Lines | 179 | for( auto it = sessions.constBegin(); it != sessions.constEnd(); ++it ) { | |||
124 | if ( ( it->name == data ) || ( it->uuid.toString() == data ) ) { | 180 | if ( ( it->name == data ) || ( it->uuid.toString() == data ) ) { | ||
125 | const KDevelop::SessionInfo& sessionRef = *it; | 181 | const KDevelop::SessionInfo& sessionRef = *it; | ||
126 | return &sessionRef; | 182 | return &sessionRef; | ||
127 | } | 183 | } | ||
128 | } | 184 | } | ||
129 | return 0; | 185 | return 0; | ||
130 | } | 186 | } | ||
131 | 187 | | |||
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 | 188 | /// Performs a DBus call to open the given @p files in the running kdev instance identified by @p pid | ||
166 | /// Returns the exit status | 189 | /// Returns the exit status | ||
167 | static int openFilesInRunningInstance(const QVector<UrlInfo>& files, qint64 pid) | 190 | static int openFilesInRunningInstance(const QVector<UrlInfo>& files, qint64 pid) | ||
168 | { | 191 | { | ||
169 | const QString service = QString("org.kdevelop.kdevelop-%1").arg(pid); | 192 | const QString service = QString("org.kdevelop.kdevelop-%1").arg(pid); | ||
170 | QDBusInterface iface(service, "/org/kdevelop/DocumentController", "org.kdevelop.DocumentController"); | 193 | QDBusInterface iface(service, "/org/kdevelop/DocumentController", "org.kdevelop.DocumentController"); | ||
171 | 194 | | |||
172 | QStringList urls; | 195 | QStringList urls; | ||
▲ Show 20 Lines • Show All 285 Lines • ▼ Show 20 Line(s) | 465 | { | |||
458 | return 0; | 481 | return 0; | ||
459 | } | 482 | } | ||
460 | 483 | | |||
461 | // Handle extra arguments, which stand for files to open | 484 | // Handle extra arguments, which stand for files to open | ||
462 | QVector<UrlInfo> initialFiles; | 485 | QVector<UrlInfo> initialFiles; | ||
463 | foreach (const QString &file, parser.positionalArguments()) { | 486 | foreach (const QString &file, parser.positionalArguments()) { | ||
464 | initialFiles.append(UrlInfo(file)); | 487 | initialFiles.append(UrlInfo(file)); | ||
465 | } | 488 | } | ||
466 | if ( ! initialFiles.isEmpty() && ! parser.isSet("new-session") ) | 489 | | ||
490 | if (!parser.isSet("new-session")) { | ||||
491 | #if KDEVELOP_SINGLE_APP | ||||
492 | if (app.isRunning()) { | ||||
493 | bool success = app.sendMessage(serializeOpenFilesMessage(initialFiles)); | ||||
494 | if (success) { | ||||
495 | return 0; | ||||
496 | } | ||||
497 | } | ||||
498 | #endif | ||||
499 | | ||||
500 | if ( ! initialFiles.isEmpty() ) | ||||
467 | { | 501 | { | ||
468 | qint64 pid = -1; | 502 | qint64 pid = -1; | ||
469 | if (parser.isSet("open-session")) { | 503 | if (parser.isSet("open-session")) { | ||
470 | const QString session = findSessionId(parser.value("open-session")); | 504 | const QString session = findSessionId(parser.value("open-session")); | ||
471 | if (session.isEmpty()) { | 505 | if (session.isEmpty()) { | ||
472 | return 1; | 506 | return 1; | ||
473 | } else if (KDevelop::SessionController::isSessionRunning(session)) { | 507 | } else if (KDevelop::SessionController::isSessionRunning(session)) { | ||
474 | pid = findSessionPid(session); | 508 | pid = findSessionPid(session); | ||
475 | } | 509 | } | ||
476 | } else { | 510 | } else { | ||
477 | pid = getRunningSessionPid(); | 511 | pid = getRunningSessionPid(); | ||
478 | } | 512 | } | ||
479 | if ( pid > 0 ) { | 513 | if ( pid > 0 ) { | ||
480 | return openFilesInRunningInstance(initialFiles, pid); | 514 | return openFilesInRunningInstance(initialFiles, pid); | ||
481 | } | 515 | } | ||
482 | // else there are no running sessions, and the generated list of files will be opened below. | 516 | // else there are no running sessions, and the generated list of files will be opened below. | ||
483 | } | 517 | } | ||
518 | } | ||||
484 | 519 | | |||
485 | // if empty, restart kdevelop with last active session, see SessionController::defaultSessionId | 520 | // if empty, restart kdevelop with last active session, see SessionController::defaultSessionId | ||
486 | QString session; | 521 | QString session; | ||
487 | 522 | | |||
488 | uint nRunningSessions = 0; | 523 | uint nRunningSessions = 0; | ||
489 | foreach(const KDevelop::SessionInfo& si, KDevelop::SessionController::availableSessionInfos()) | 524 | foreach(const KDevelop::SessionInfo& si, KDevelop::SessionController::availableSessionInfos()) | ||
490 | if(KDevelop::SessionController::isSessionRunning(si.uuid.toString())) | 525 | if(KDevelop::SessionController::isSessionRunning(si.uuid.toString())) | ||
491 | ++nRunningSessions; | 526 | ++nRunningSessions; | ||
▲ Show 20 Lines • Show All 203 Lines • ▼ Show 20 Line(s) | 683 | if ( parser.isSet("debug") ) { | |||
695 | } | 730 | } | ||
696 | 731 | | |||
697 | type->configureLaunchFromCmdLineArguments(launch->config(), debugArgs); | 732 | type->configureLaunchFromCmdLineArguments(launch->config(), debugArgs); | ||
698 | launch->config().writeEntry("Break on Start", true); | 733 | launch->config().writeEntry("Break on Start", true); | ||
699 | core->runControllerInternal()->setDefaultLaunch(launch); | 734 | core->runControllerInternal()->setDefaultLaunch(launch); | ||
700 | 735 | | |||
701 | core->runControllerInternal()->execute("debug", launch); | 736 | core->runControllerInternal()->execute("debug", launch); | ||
702 | } else { | 737 | } else { | ||
703 | foreach ( const UrlInfo& file, initialFiles ) { | 738 | 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 | } | 739 | } | ||
709 | 740 | | |||
741 | #if KDEVELOP_SINGLE_APP | ||||
742 | // Set up remote arguments. | ||||
743 | QObject::connect(&app, &SharedTools::QtSingleApplication::messageReceived, | ||||
744 | &app, &KDevelopApplication::remoteArguments); | ||||
745 | | ||||
746 | QObject::connect(&app, &SharedTools::QtSingleApplication::fileOpenRequest, | ||||
747 | &app, &KDevelopApplication::fileOpenRequested); | ||||
748 | #endif | ||||
749 | | ||||
750 | | ||||
710 | #ifdef WITH_WELCOMEPAGE | 751 | #ifdef WITH_WELCOMEPAGE | ||
711 | // make it possible to disable the welcome page, useful for valgrind runs e.g. | 752 | // make it possible to disable the welcome page, useful for valgrind runs e.g. | ||
712 | if (!qEnvironmentVariableIsSet("KDEV_DISABLE_WELCOMEPAGE")) { | 753 | if (!qEnvironmentVariableIsSet("KDEV_DISABLE_WELCOMEPAGE")) { | ||
713 | trySetupWelcomePageView(); | 754 | trySetupWelcomePageView(); | ||
714 | } | 755 | } | ||
715 | #endif | 756 | #endif | ||
716 | 757 | | |||
717 | qCDebug(APP) << "Done startup" << "- took:" << timer.elapsed() << "ms"; | 758 | qCDebug(APP) << "Done startup" << "- took:" << timer.elapsed() << "ms"; | ||
718 | timer.invalidate(); | 759 | timer.invalidate(); | ||
719 | 760 | | |||
720 | return app.exec(); | 761 | return app.exec(); | ||
721 | } | 762 | } |