diff --git a/src/app/main.cpp b/src/app/main.cpp index 71d00d320b510d8d99a734cc0cb4252a6a45e841..1db6fc2bdaf8ffe4cc397660d6af70be97fdba2a 100644 --- a/src/app/main.cpp +++ b/src/app/main.cpp @@ -71,7 +71,8 @@ static const char fixedOptionsC[] = " -version Display program version\n" " -client Attempt to connect to already running first instance\n" " -settingspath <path> Override the default path where user settings are stored\n" -" -pid <pid> Attempt to connect to instance given by pid\n"; +" -pid <pid> Attempt to connect to instance given by pid\n" +" -block Block until editor is closed\n"; static const char HELP_OPTION1[] = "-h"; @@ -82,6 +83,7 @@ static const char VERSION_OPTION[] = "-version"; static const char CLIENT_OPTION[] = "-client"; static const char SETTINGS_OPTION[] = "-settingspath"; static const char PID_OPTION[] = "-pid"; +static const char BLOCK_OPTION[] = "-block"; typedef QList<PluginSpec *> PluginSpecSet; @@ -409,6 +411,7 @@ int main(int argc, char **argv) appOptions.insert(QLatin1String(VERSION_OPTION), false); appOptions.insert(QLatin1String(CLIENT_OPTION), false); appOptions.insert(QLatin1String(PID_OPTION), true); + appOptions.insert(QLatin1String(BLOCK_OPTION), false); QString errorMessage; if (!PluginManager::parseOptions(arguments, appOptions, &foundAppOptions, &errorMessage)) { displayError(errorMessage); @@ -456,7 +459,10 @@ int main(int argc, char **argv) pid = tmpPid; } - if (app.isRunning() && (pid != -1 || foundAppOptions.contains(QLatin1String(CLIENT_OPTION)))) { + bool isBlock = foundAppOptions.contains(QLatin1String(BLOCK_OPTION)); + if (app.isRunning() && (pid != -1 || isBlock + || foundAppOptions.contains(QLatin1String(CLIENT_OPTION)))) { + app.setBlock(isBlock); if (app.sendMessage(PluginManager::serializedArguments(), 5000 /*timeout*/, pid)) return 0; @@ -489,8 +495,8 @@ int main(int argc, char **argv) // Set up lock and remote arguments. app.initialize(); - QObject::connect(&app, SIGNAL(messageReceived(QString)), - &pluginManager, SLOT(remoteArguments(QString))); + QObject::connect(&app, SIGNAL(messageReceived(QString,QObject*)), + &pluginManager, SLOT(remoteArguments(QString,QObject*))); QObject::connect(&app, SIGNAL(fileOpenRequest(QString)), coreplugin->plugin(), SLOT(fileOpenRequest(QString))); diff --git a/src/libs/extensionsystem/iplugin.cpp b/src/libs/extensionsystem/iplugin.cpp index 062e9efdee9b3883c09f6a8a005c279d26574109..b3cda5f508e49fd0bb2d831f26c260c980c7cef5 100644 --- a/src/libs/extensionsystem/iplugin.cpp +++ b/src/libs/extensionsystem/iplugin.cpp @@ -157,6 +157,19 @@ \sa asynchronousShutdownFinished() */ +/*! + \fn QObject *IPlugin::remoteCommand(const QStringList &options, const QStringList &arguments) + \brief When \QC is executed with the -client argument while already another instance of \QC + is running, this method of plugins is called in the running instance. + + Plugin-specific arguments are passed in \a options, while the rest of the + arguments are passed in \a arguments. + + \returns a QObject that blocks the command until it is destroyed, if -block is used. + + \sa PluginManager::serializedArguments() +*/ + /*! \fn void IPlugin::asynchronousShutdownFinished() Sent by the plugin implementation after a asynchronous shutdown diff --git a/src/libs/extensionsystem/iplugin.h b/src/libs/extensionsystem/iplugin.h index 1a49e351acf2d1381492984972a2e76d25f1dc84..1b3e537b242d30277e01ef1ff57103ba16058a74 100644 --- a/src/libs/extensionsystem/iplugin.h +++ b/src/libs/extensionsystem/iplugin.h @@ -64,7 +64,7 @@ public: virtual void extensionsInitialized() = 0; virtual bool delayedInitialize() { return false; } virtual ShutdownFlag aboutToShutdown() { return SynchronousShutdown; } - virtual void remoteCommand(const QStringList & /* options */, const QStringList & /* arguments */) { } + virtual QObject *remoteCommand(const QStringList & /* options */, const QStringList & /* arguments */) { return 0; } PluginSpec *pluginSpec() const; diff --git a/src/libs/extensionsystem/pluginmanager.cpp b/src/libs/extensionsystem/pluginmanager.cpp index 8829f757e7889b7b924898a9a39d704a3fb1af1d..63208da0573e68f2b6d8673b9f2d761a2e99a2f8 100644 --- a/src/libs/extensionsystem/pluginmanager.cpp +++ b/src/libs/extensionsystem/pluginmanager.cpp @@ -532,13 +532,16 @@ static QStringList subList(const QStringList &in, const QString &key) } /*! - \fn PluginManager::remoteArguments(const QString &argument) + \fn PluginManager::remoteArguments(const QString &argument, QObject *socket) Parses the options encoded by serializedArguments() const and passes them on to the respective plugins along with the arguments. + + \a socket is passed for disconnecting the peer when the operation is done (for example, + document is closed) for supporting the -block flag. */ -void PluginManager::remoteArguments(const QString &serializedArgument) +void PluginManager::remoteArguments(const QString &serializedArgument, QObject *socket) { if (serializedArgument.isEmpty()) return; @@ -547,9 +550,15 @@ void PluginManager::remoteArguments(const QString &serializedArgument) foreach (const PluginSpec *ps, plugins()) { if (ps->state() == PluginSpec::Running) { const QStringList pluginOptions = subList(serializedArguments, QLatin1Char(':') + ps->name()); - ps->plugin()->remoteCommand(pluginOptions, arguments); + QObject *socketParent = ps->plugin()->remoteCommand(pluginOptions, arguments); + if (socketParent && socket) { + socket->setParent(socketParent); + socket = 0; + } } } + if (socket) + delete socket; } /*! diff --git a/src/libs/extensionsystem/pluginmanager.h b/src/libs/extensionsystem/pluginmanager.h index 41de4c559141b9e5cddb9c1daa3a7e9b5b14a113..e20159abfca8fbb510cef2f661f1a1a82a124dfb 100644 --- a/src/libs/extensionsystem/pluginmanager.h +++ b/src/libs/extensionsystem/pluginmanager.h @@ -137,7 +137,7 @@ signals: void initializationDone(); public slots: - void remoteArguments(const QString &serializedArguments); + void remoteArguments(const QString &serializedArguments, QObject *socket); void shutdown(); private slots: diff --git a/src/plugins/coreplugin/coreplugin.cpp b/src/plugins/coreplugin/coreplugin.cpp index 25ebd22851331c3d55fe208b840ce9384b469be1..d170ddb64815545cbaea407d2ee3013fa9f8de44 100644 --- a/src/plugins/coreplugin/coreplugin.cpp +++ b/src/plugins/coreplugin/coreplugin.cpp @@ -119,10 +119,12 @@ bool CorePlugin::delayedInitialize() return true; } -void CorePlugin::remoteCommand(const QStringList & /* options */, const QStringList &args) +QObject *CorePlugin::remoteCommand(const QStringList & /* options */, const QStringList &args) { - m_mainWindow->openFiles(args, Core::ICore::OpenFilesFlags(ICore::SwitchMode | ICore::CanContainLineNumbers)); + IDocument *res = m_mainWindow->openFiles( + args, ICore::OpenFilesFlags(ICore::SwitchMode | ICore::CanContainLineNumbers)); m_mainWindow->activateWindow(); + return res; } void CorePlugin::fileOpenRequest(const QString &f) diff --git a/src/plugins/coreplugin/coreplugin.h b/src/plugins/coreplugin/coreplugin.h index d7fbef0f2a0a75108b7ff0869e1986f5e4efa23a..b9ca64b855273af51adbe515282afa01d43f9404 100644 --- a/src/plugins/coreplugin/coreplugin.h +++ b/src/plugins/coreplugin/coreplugin.h @@ -52,7 +52,7 @@ public: void extensionsInitialized(); bool delayedInitialize(); ShutdownFlag aboutToShutdown(); - void remoteCommand(const QStringList & /* options */, const QStringList &args); + QObject *remoteCommand(const QStringList & /* options */, const QStringList &args); public slots: void fileOpenRequest(const QString&); diff --git a/src/plugins/coreplugin/mainwindow.cpp b/src/plugins/coreplugin/mainwindow.cpp index e7e2abc6f904af34cd0a749cb9ee17f24c4f235a..862e6e77d3e272fe6166065f9eaaba87014bfa86 100644 --- a/src/plugins/coreplugin/mainwindow.cpp +++ b/src/plugins/coreplugin/mainwindow.cpp @@ -831,31 +831,51 @@ static IDocumentFactory *findDocumentFactory(const QList<IDocumentFactory*> &fil return 0; } -// opens either an editor or loads a project -void MainWindow::openFiles(const QStringList &fileNames, ICore::OpenFilesFlags flags) +/*! Either opens \a fileNames with editors or loads a project. + * + * \a flags can be used to stop on first failure, indicate that a file name + * might include line numbers and/or switch mode to edit mode. + * + * \returns the first opened document. Required to support the -block flag + * for client mode. + * + * \sa IPlugin::remoteArguments() + */ +IDocument *MainWindow::openFiles(const QStringList &fileNames, ICore::OpenFilesFlags flags) { QList<IDocumentFactory*> nonEditorFileFactories = getNonEditorDocumentFactories(); + IDocument *res = 0; foreach (const QString &fileName, fileNames) { const QFileInfo fi(fileName); const QString absoluteFilePath = fi.absoluteFilePath(); if (IDocumentFactory *documentFactory = findDocumentFactory(nonEditorFileFactories, mimeDatabase(), fi)) { - Core::IDocument *document = documentFactory->open(absoluteFilePath); - if (!document && (flags & ICore::StopOnLoadFail)) - return; - if (document && (flags & ICore::SwitchMode)) - ModeManager::activateMode(Id(Core::Constants::MODE_EDIT)); + IDocument *document = documentFactory->open(absoluteFilePath); + if (!document) { + if (flags & ICore::StopOnLoadFail) + return res; + } else { + if (!res) + res = document; + if (flags & ICore::SwitchMode) + ModeManager::activateMode(Id(Core::Constants::MODE_EDIT)); + } } else { QFlags<EditorManager::OpenEditorFlag> emFlags; if (flags & ICore::SwitchMode) emFlags = EditorManager::ModeSwitch; if (flags & ICore::CanContainLineNumbers) emFlags |= EditorManager::CanContainLineNumber; - Core::IEditor *editor = EditorManager::openEditor(absoluteFilePath, Id(), emFlags); - if (!editor && (flags & ICore::StopOnLoadFail)) - return; + IEditor *editor = EditorManager::openEditor(absoluteFilePath, Id(), emFlags); + if (!editor) { + if (flags & ICore::StopOnLoadFail) + return res; + } else if (!res) { + res = editor->document(); + } } } + return res; } void MainWindow::setFocusToEditor() diff --git a/src/plugins/coreplugin/mainwindow.h b/src/plugins/coreplugin/mainwindow.h index 97a4447d9d55f01f43fcb69362d7c57c795642b2..0fc5c4172dd0976c33b01a5fca975493dbc2c22a 100644 --- a/src/plugins/coreplugin/mainwindow.h +++ b/src/plugins/coreplugin/mainwindow.h @@ -53,6 +53,7 @@ class EditorManager; class ExternalToolManager; class DocumentManager; class HelpManager; +class IDocument; class IWizard; class MessageManager; class MimeDatabase; @@ -95,7 +96,7 @@ public: void removeContextObject(IContext *contex); void resetContext(); - void openFiles(const QStringList &fileNames, ICore::OpenFilesFlags flags); + Core::IDocument *openFiles(const QStringList &fileNames, ICore::OpenFilesFlags flags); Core::ActionManager *actionManager() const; Core::MessageManager *messageManager() const; diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index 3a2a9175e48eb3f7d325a2bf18186b5f6e8fb052..8227d4268321dc9810ee4fc5f8fc04091e2d7313 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -3441,10 +3441,11 @@ IPlugin::ShutdownFlag DebuggerPlugin::aboutToShutdown() return SynchronousShutdown; } -void DebuggerPlugin::remoteCommand(const QStringList &options, +QObject *DebuggerPlugin::remoteCommand(const QStringList &options, const QStringList &list) { theDebuggerCore->remoteCommand(options, list); + return 0; } DebuggerRunControl *DebuggerPlugin::createDebugger diff --git a/src/plugins/debugger/debuggerplugin.h b/src/plugins/debugger/debuggerplugin.h index 73e221a999a4b745beadb21ee9d2737671d74dd3..1c3925486bc3ee492a05095c6670037258dde6da 100644 --- a/src/plugins/debugger/debuggerplugin.h +++ b/src/plugins/debugger/debuggerplugin.h @@ -71,7 +71,7 @@ public: private: // IPlugin implementation. bool initialize(const QStringList &arguments, QString *errorMessage); - void remoteCommand(const QStringList &options, const QStringList &arguments); + QObject *remoteCommand(const QStringList &options, const QStringList &arguments); ShutdownFlag aboutToShutdown(); void extensionsInitialized(); diff --git a/src/shared/qtsingleapplication/qtlocalpeer.cpp b/src/shared/qtsingleapplication/qtlocalpeer.cpp index 6410db3195a5220655cd18181f2a7b67c5f15630..c1c68938af50ff7fc98c12fdbab82210acbbb124 100644 --- a/src/shared/qtsingleapplication/qtlocalpeer.cpp +++ b/src/shared/qtsingleapplication/qtlocalpeer.cpp @@ -99,7 +99,7 @@ bool QtLocalPeer::isClient() return false; } -bool QtLocalPeer::sendMessage(const QString &message, int timeout) +bool QtLocalPeer::sendMessage(const QString &message, int timeout, bool block) { if (!isClient()) return false; @@ -129,6 +129,8 @@ bool QtLocalPeer::sendMessage(const QString &message, int timeout) bool res = socket.waitForBytesWritten(timeout); res &= socket.waitForReadyRead(timeout); // wait for ack res &= (socket.read(qstrlen(ack)) == ack); + if (block) // block until peer disconnects + socket.waitForDisconnected(-1); return res; } @@ -168,8 +170,7 @@ void QtLocalPeer::receiveConnection() QString message = QString::fromUtf8(uMsg.constData(), uMsg.size()); socket->write(ack, qstrlen(ack)); socket->waitForBytesWritten(1000); - delete socket; - emit messageReceived(message); // ##(might take a long time to return) + emit messageReceived(message, socket); // ##(might take a long time to return) } } // namespace SharedTools diff --git a/src/shared/qtsingleapplication/qtlocalpeer.h b/src/shared/qtsingleapplication/qtlocalpeer.h index 14d2d148069cdc6f3145f01b08d23587833f3463..e721a05de9a538ccbefe1623c3619f4fdf0a4009 100644 --- a/src/shared/qtsingleapplication/qtlocalpeer.h +++ b/src/shared/qtsingleapplication/qtlocalpeer.h @@ -42,12 +42,12 @@ class QtLocalPeer : public QObject public: explicit QtLocalPeer(QObject *parent = 0, const QString &appId = QString()); bool isClient(); - bool sendMessage(const QString &message, int timeout); + bool sendMessage(const QString &message, int timeout, bool block); QString applicationId() const { return id; } Q_SIGNALS: - void messageReceived(const QString &message); + void messageReceived(const QString &message, QObject *socket); protected Q_SLOTS: void receiveConnection(); diff --git a/src/shared/qtsingleapplication/qtsingleapplication.cpp b/src/shared/qtsingleapplication/qtsingleapplication.cpp index 8fcf2152795571644f407656d8460f076b5e3fec..f00ebea53c37931776a280835cc7dc2b88b70091 100644 --- a/src/shared/qtsingleapplication/qtsingleapplication.cpp +++ b/src/shared/qtsingleapplication/qtsingleapplication.cpp @@ -38,10 +38,11 @@ namespace SharedTools { void QtSingleApplication::sysInit(const QString &appId) { actWin = 0; + block = false; firstPeer = new QtLocalPeer(this, appId); - connect(firstPeer, SIGNAL(messageReceived(QString)), SIGNAL(messageReceived(QString))); + connect(firstPeer, SIGNAL(messageReceived(QString,QObject*)), SIGNAL(messageReceived(QString,QObject*))); pidPeer = new QtLocalPeer(this, appId + QLatin1Char('-') + QString::number(QCoreApplication::applicationPid(), 10)); - connect(pidPeer, SIGNAL(messageReceived(QString)), SIGNAL(messageReceived(QString))); + connect(pidPeer, SIGNAL(messageReceived(QString,QObject*)), SIGNAL(messageReceived(QString,QObject*))); } @@ -87,10 +88,10 @@ void QtSingleApplication::initialize(bool) bool QtSingleApplication::sendMessage(const QString &message, int timeout, qint64 pid) { if (pid == -1) - return firstPeer->sendMessage(message, timeout); + return firstPeer->sendMessage(message, timeout, block); QtLocalPeer peer(this, appId + QLatin1Char('-') + QString::number(pid, 10)); - return peer.sendMessage(message, timeout); + return peer.sendMessage(message, timeout, block); } QString QtSingleApplication::id() const @@ -103,15 +104,20 @@ QString QtSingleApplication::applicationId() const return appId; } +void QtSingleApplication::setBlock(bool value) +{ + block = value; +} + void QtSingleApplication::setActivationWindow(QWidget *aw, bool activateOnMessage) { actWin = aw; if (activateOnMessage) { - connect(firstPeer, SIGNAL(messageReceived(QString)), this, SLOT(activateWindow())); - connect(pidPeer, SIGNAL(messageReceived(QString)), this, SLOT(activateWindow())); + connect(firstPeer, SIGNAL(messageReceived(QString,QObject*)), this, SLOT(activateWindow())); + connect(pidPeer, SIGNAL(messageReceived(QString,QObject*)), this, SLOT(activateWindow())); } else { - disconnect(firstPeer, SIGNAL(messageReceived(QString)), this, SLOT(activateWindow())); - disconnect(pidPeer, SIGNAL(messageReceived(QString)), this, SLOT(activateWindow())); + disconnect(firstPeer, SIGNAL(messageReceived(QString,QObject*)), this, SLOT(activateWindow())); + disconnect(pidPeer, SIGNAL(messageReceived(QString,QObject*)), this, SLOT(activateWindow())); } } diff --git a/src/shared/qtsingleapplication/qtsingleapplication.h b/src/shared/qtsingleapplication/qtsingleapplication.h index 5baebd5c9adfec6968980840a293e738d2979e98..47f290a925974f29fe86e8367c44001e101e0041 100644 --- a/src/shared/qtsingleapplication/qtsingleapplication.h +++ b/src/shared/qtsingleapplication/qtsingleapplication.h @@ -50,6 +50,7 @@ public: bool event(QEvent *event); QString applicationId() const; + void setBlock(bool value); public Q_SLOTS: bool sendMessage(const QString &message, int timeout = 5000, qint64 pid = -1); @@ -61,7 +62,7 @@ public: // end obsolete methods Q_SIGNALS: - void messageReceived(const QString &message); + void messageReceived(const QString &message, QObject *socket); void fileOpenRequest(const QString &file); private: @@ -70,6 +71,7 @@ private: QtLocalPeer *pidPeer; QWidget *actWin; QString appId; + bool block; }; } // namespace SharedTools