diff --git a/CMakeLists.txt b/CMakeLists.txt index 7633f4f..81e896f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,8 +1,6 @@ cmake_minimum_required(VERSION 3.20) project(quickshell VERSION "0.2.1" LANGUAGES CXX C) -set(UNRELEASED_FEATURES) - set(QT_MIN_VERSION "6.6.0") set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) diff --git a/changelog/next.md b/changelog/next.md index 30e998b..0cdff57 100644 --- a/changelog/next.md +++ b/changelog/next.md @@ -22,8 +22,6 @@ set shell id. - Added pipewire audio peak detection. - Added initial support for network management. - Added support for grabbing focus from popup windows. -- Added support for IPC signal listeners. -- Added Quickshell version checking and version gated preprocessing. ## Other Changes @@ -42,7 +40,6 @@ set shell id. - Fixed missing signals for system tray item title and description updates. - Fixed asynchronous loaders not working after reload. - Fixed asynchronous loaders not working before window creation. -- Fixed memory leak in IPC handlers. ## Packaging Changes diff --git a/src/build/build.hpp.in b/src/build/build.hpp.in index 66fb664..075abd1 100644 --- a/src/build/build.hpp.in +++ b/src/build/build.hpp.in @@ -1,11 +1,6 @@ #pragma once // NOLINTBEGIN -#define QS_VERSION "@quickshell_VERSION@" -#define QS_VERSION_MAJOR @quickshell_VERSION_MAJOR@ -#define QS_VERSION_MINOR @quickshell_VERSION_MINOR@ -#define QS_VERSION_PATCH @quickshell_VERSION_PATCH@ -#define QS_UNRELEASED_FEATURES "@UNRELEASED_FEATURES@" #define GIT_REVISION "@GIT_REVISION@" #define DISTRIBUTOR "@DISTRIBUTOR@" #define DISTRIBUTOR_DEBUGINFO_AVAILABLE @DEBUGINFO_AVAILABLE@ diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index fb63f40..bbfb8c4 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -12,7 +12,6 @@ qt_add_library(quickshell-core STATIC singleton.cpp generation.cpp scan.cpp - scanenv.cpp qsintercept.cpp incubator.cpp lazyloader.cpp @@ -52,7 +51,7 @@ qt_add_qml_module(quickshell-core install_qml_module(quickshell-core) -target_link_libraries(quickshell-core PRIVATE Qt::Quick Qt::QuickPrivate Qt::Widgets quickshell-build) +target_link_libraries(quickshell-core PRIVATE Qt::Quick Qt::QuickPrivate Qt::Widgets) qs_module_pch(quickshell-core SET large) diff --git a/src/core/qmlglobal.cpp b/src/core/qmlglobal.cpp index 03fb818..07238f6 100644 --- a/src/core/qmlglobal.cpp +++ b/src/core/qmlglobal.cpp @@ -29,7 +29,6 @@ #include "paths.hpp" #include "qmlscreen.hpp" #include "rootwrapper.hpp" -#include "scanenv.hpp" QuickshellSettings::QuickshellSettings() { QObject::connect( @@ -314,14 +313,6 @@ QString QuickshellGlobal::iconPath(const QString& icon, const QString& fallback) return IconImageProvider::requestString(icon, "", fallback); } -bool QuickshellGlobal::hasVersion(qint32 major, qint32 minor, const QStringList& features) { - return qs::scan::env::PreprocEnv::hasVersion(major, minor, features); -} - -bool QuickshellGlobal::hasVersion(qint32 major, qint32 minor) { - return QuickshellGlobal::hasVersion(major, minor, QStringList()); -} - QuickshellGlobal* QuickshellGlobal::create(QQmlEngine* engine, QJSEngine* /*unused*/) { auto* qsg = new QuickshellGlobal(); auto* generation = EngineGeneration::findEngineGeneration(engine); diff --git a/src/core/qmlglobal.hpp b/src/core/qmlglobal.hpp index 3ca70be..1fc363b 100644 --- a/src/core/qmlglobal.hpp +++ b/src/core/qmlglobal.hpp @@ -217,21 +217,6 @@ public: /// /// The popup can also be blocked by setting `QS_NO_RELOAD_POPUP=1`. Q_INVOKABLE void inhibitReloadPopup() { this->mInhibitReloadPopup = true; } - /// Check if Quickshell's version is at least `major.minor` and the listed - /// unreleased features are available. If Quickshell is newer than the given version - /// it is assumed that all unreleased features are present. The unreleased feature list - /// may be omitted. - /// - /// > [!NOTE] You can feature gate code blocks using Quickshell's preprocessor which - /// > has the same function available. - /// > - /// > ```qml - /// > //@ if hasVersion(0, 3, ["feature"]) - /// > ... - /// > //@ endif - /// > ``` - Q_INVOKABLE static bool hasVersion(qint32 major, qint32 minor, const QStringList& features); - Q_INVOKABLE static bool hasVersion(qint32 major, qint32 minor); void clearReloadPopupInhibit() { this->mInhibitReloadPopup = false; } [[nodiscard]] bool isReloadPopupInhibited() const { return this->mInhibitReloadPopup; } diff --git a/src/core/rootwrapper.cpp b/src/core/rootwrapper.cpp index 1e75819..25c46cc 100644 --- a/src/core/rootwrapper.cpp +++ b/src/core/rootwrapper.cpp @@ -63,6 +63,9 @@ void RootWrapper::reloadGraph(bool hard) { qs::core::QmlToolingSupport::updateTooling(rootPath, scanner); this->configDirWatcher.addPath(rootPath.path()); + auto* generation = new EngineGeneration(rootPath, std::move(scanner)); + generation->wrapper = this; + // todo: move into EngineGeneration if (this->generation != nullptr) { qInfo() << "Reloading configuration..."; @@ -71,33 +74,6 @@ void RootWrapper::reloadGraph(bool hard) { QDir::setCurrent(this->originalWorkingDirectory); - if (!scanner.scanErrors.isEmpty()) { - qCritical() << "Failed to load configuration"; - QString errorString = "Failed to load configuration"; - for (auto& error: scanner.scanErrors) { - const auto& file = error.file; - QString rel; - if (file.startsWith(rootPath.path() % '/')) { - rel = '@' % file.sliced(rootPath.path().length() + 1); - } else { - rel = file; - } - - auto msg = " error in " % rel % '[' % QString::number(error.line) % ":0]: " % error.message; - errorString += '\n' % msg; - qCritical().noquote() << msg; - } - - if (this->generation != nullptr && this->generation->qsgInstance != nullptr) { - emit this->generation->qsgInstance->reloadFailed(errorString); - } - - return; - } - - auto* generation = new EngineGeneration(rootPath, std::move(scanner)); - generation->wrapper = this; - QUrl url; url.setScheme("qs"); url.setPath("@/qs/" % rootFile.fileName()); diff --git a/src/core/scan.cpp b/src/core/scan.cpp index 8ca1f51..453b7dc 100644 --- a/src/core/scan.cpp +++ b/src/core/scan.cpp @@ -1,11 +1,9 @@ #include "scan.hpp" #include -#include #include #include #include -#include #include #include #include @@ -17,7 +15,6 @@ #include #include "logcat.hpp" -#include "scanenv.hpp" QS_LOGGING_CATEGORY(logQmlScanner, "quickshell.qmlscanner", QtWarningMsg); @@ -118,113 +115,51 @@ bool QmlScanner::scanQmlFile(const QString& path, bool& singleton, bool& interna auto stream = QTextStream(&file); auto imports = QVector(); - bool inHeader = false; - auto ifScopes = QVector(); - bool sourceMasked = false; - int lineNum = 0; - QString overrideText; - bool isOverridden = false; - - auto pragmaEngine = QJSEngine(); - pragmaEngine.globalObject().setPrototype( - pragmaEngine.newQObject(new qs::scan::env::PreprocEnv()) - ); - - auto postError = [&, this](QString error) { - this->scanErrors.append({.file = path, .message = std::move(error), .line = lineNum}); - }; - while (!stream.atEnd()) { - ++lineNum; - bool hideMask = false; - auto rawLine = stream.readLine(); - auto line = rawLine.trimmed(); - if (!sourceMasked && inHeader) { - if (!singleton && line == "pragma Singleton") { - singleton = true; - } else if (line.startsWith("import")) { - // we dont care about "import qs" as we always load the root folder - if (auto importCursor = line.indexOf(" qs."); importCursor != -1) { - importCursor += 4; - QString path; + auto line = stream.readLine().trimmed(); + if (!singleton && line == "pragma Singleton") { + singleton = true; + } else if (!internal && line == "//@ pragma Internal") { + internal = true; + } else if (line.startsWith("import")) { + // we dont care about "import qs" as we always load the root folder + if (auto importCursor = line.indexOf(" qs."); importCursor != -1) { + importCursor += 4; + QString path; - while (importCursor != line.length()) { - auto c = line.at(importCursor); - if (c == '.') c = '/'; - else if (c == ' ') break; - else if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') - || c == '_') - { - } else { - qCWarning(logQmlScanner) << "Import line contains invalid characters: " << line; - goto next; - } - - path.append(c); - importCursor += 1; + while (importCursor != line.length()) { + auto c = line.at(importCursor); + if (c == '.') c = '/'; + else if (c == ' ') break; + else if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') + || c == '_') + { + } else { + qCWarning(logQmlScanner) << "Import line contains invalid characters: " << line; + goto next; } - imports.append(this->rootPath.filePath(path)); - } else if (auto startQuot = line.indexOf('"'); - startQuot != -1 && line.length() >= startQuot + 3) - { - auto endQuot = line.indexOf('"', startQuot + 1); - if (endQuot == -1) continue; - - auto name = line.sliced(startQuot + 1, endQuot - startQuot - 1); - imports.push_back(name); + path.append(c); + importCursor += 1; } - } else if (!internal && line == "//@ pragma Internal") { - internal = true; - } else if (line.contains('{')) { - inHeader = true; + + imports.append(this->rootPath.filePath(path)); + } else if (auto startQuot = line.indexOf('"'); + startQuot != -1 && line.length() >= startQuot + 3) + { + auto endQuot = line.indexOf('"', startQuot + 1); + if (endQuot == -1) continue; + + auto name = line.sliced(startQuot + 1, endQuot - startQuot - 1); + imports.push_back(name); } - } - - if (line.startsWith("//@ if ")) { - auto code = line.sliced(7); - auto value = pragmaEngine.evaluate(code, path, 1234); - bool mask = true; - - if (value.isError()) { - postError(QString("Evaluating if: %0").arg(value.toString())); - } else if (!value.isBool()) { - postError(QString("If expression \"%0\" is not a boolean").arg(value.toString())); - } else if (value.toBool()) { - mask = false; - } - if (!sourceMasked && mask) hideMask = true; - mask = sourceMasked || mask; // cant unmask if a nested if passes - ifScopes.append(mask); - if (mask) isOverridden = true; - sourceMasked = mask; - } else if (line.startsWith("//@ endif")) { - if (ifScopes.isEmpty()) { - postError("endif without matching if"); - } else { - ifScopes.pop_back(); - - if (ifScopes.isEmpty()) sourceMasked = false; - else sourceMasked = ifScopes.last(); - } - } - - if (!hideMask && sourceMasked) overrideText.append("// MASKED: " % rawLine % '\n'); - else overrideText.append(rawLine % '\n'); + } else if (line.contains('{')) break; next:; } - if (!ifScopes.isEmpty()) { - postError("unclosed preprocessor if block"); - } - file.close(); - if (isOverridden) { - this->fileIntercepts.insert(path, overrideText); - } - if (logQmlScanner().isDebugEnabled() && !imports.isEmpty()) { qCDebug(logQmlScanner) << "Found imports" << imports; } diff --git a/src/core/scan.hpp b/src/core/scan.hpp index 29f8f6a..2dc8c3c 100644 --- a/src/core/scan.hpp +++ b/src/core/scan.hpp @@ -23,14 +23,6 @@ public: QVector scannedFiles; QHash fileIntercepts; - struct ScanError { - QString file; - QString message; - int line; - }; - - QVector scanErrors; - private: QDir rootPath; diff --git a/src/core/scanenv.cpp b/src/core/scanenv.cpp deleted file mode 100644 index b8c514c..0000000 --- a/src/core/scanenv.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include "scanenv.hpp" - -#include - -#include "build.hpp" - -namespace qs::scan::env { - -bool PreprocEnv::hasVersion(int major, int minor, const QStringList& features) { - if (QS_VERSION_MAJOR > major) return true; - if (QS_VERSION_MAJOR == major && QS_VERSION_MINOR > minor) return true; - - auto availFeatures = QString(QS_UNRELEASED_FEATURES).split(';'); - - for (const auto& feature: features) { - if (!availFeatures.contains(feature)) return false; - } - - return QS_VERSION_MAJOR == major && QS_VERSION_MINOR == minor; -} - -} // namespace qs::scan::env diff --git a/src/core/scanenv.hpp b/src/core/scanenv.hpp deleted file mode 100644 index 0abde2e..0000000 --- a/src/core/scanenv.hpp +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -#include -#include -#include - -namespace qs::scan::env { - -class PreprocEnv: public QObject { - Q_OBJECT; - -public: - Q_INVOKABLE static bool - hasVersion(int major, int minor, const QStringList& features = QStringList()); -}; - -} // namespace qs::scan::env diff --git a/src/io/CMakeLists.txt b/src/io/CMakeLists.txt index 991beaa..17628d3 100644 --- a/src/io/CMakeLists.txt +++ b/src/io/CMakeLists.txt @@ -24,7 +24,7 @@ qt_add_qml_module(quickshell-io qs_add_module_deps_light(quickshell-io Quickshell) install_qml_module(quickshell-io) -target_link_libraries(quickshell-io PRIVATE Qt::Quick quickshell-ipc) +target_link_libraries(quickshell-io PRIVATE Qt::Quick) target_link_libraries(quickshell PRIVATE quickshell-ioplugin) qs_module_pch(quickshell-io) diff --git a/src/io/ipc.cpp b/src/io/ipc.cpp index c381567..768299e 100644 --- a/src/io/ipc.cpp +++ b/src/io/ipc.cpp @@ -190,14 +190,6 @@ QString WirePropertyDefinition::toString() const { return "property " % this->name % ": " % this->type; } -QString WireSignalDefinition::toString() const { - if (this->rettype.isEmpty()) { - return "signal " % this->name % "()"; - } else { - return "signal " % this->name % "(" % this->retname % ": " % this->rettype % ')'; - } -} - QString WireTargetDefinition::toString() const { QString accum = "target " % this->name; @@ -209,10 +201,6 @@ QString WireTargetDefinition::toString() const { accum += "\n " % prop.toString(); } - for (const auto& sig: this->signalFunctions) { - accum += "\n " % sig.toString(); - } - return accum; } diff --git a/src/io/ipc.hpp b/src/io/ipc.hpp index 32486d6..d2b865a 100644 --- a/src/io/ipc.hpp +++ b/src/io/ipc.hpp @@ -146,31 +146,14 @@ struct WirePropertyDefinition { DEFINE_SIMPLE_DATASTREAM_OPS(WirePropertyDefinition, data.name, data.type); -struct WireSignalDefinition { - QString name; - QString retname; - QString rettype; - - [[nodiscard]] QString toString() const; -}; - -DEFINE_SIMPLE_DATASTREAM_OPS(WireSignalDefinition, data.name, data.retname, data.rettype); - struct WireTargetDefinition { QString name; QVector functions; QVector properties; - QVector signalFunctions; [[nodiscard]] QString toString() const; }; -DEFINE_SIMPLE_DATASTREAM_OPS( - WireTargetDefinition, - data.name, - data.functions, - data.properties, - data.signalFunctions -); +DEFINE_SIMPLE_DATASTREAM_OPS(WireTargetDefinition, data.name, data.functions, data.properties); } // namespace qs::io::ipc diff --git a/src/io/ipccomm.cpp b/src/io/ipccomm.cpp index 03b688a..6c7e4f6 100644 --- a/src/io/ipccomm.cpp +++ b/src/io/ipccomm.cpp @@ -1,11 +1,9 @@ #include "ipccomm.hpp" -#include #include #include #include #include -#include #include #include @@ -20,6 +18,10 @@ using namespace qs::ipc; namespace qs::io::ipc::comm { +struct NoCurrentGeneration: std::monostate {}; +struct TargetNotFound: std::monostate {}; +struct EntryNotFound: std::monostate {}; + using QueryResponse = std::variant< std::monostate, NoCurrentGeneration, @@ -311,106 +313,4 @@ int getProperty(IpcClient* client, const QString& target, const QString& propert return -1; } -int listenToSignal(IpcClient* client, const QString& target, const QString& signal, bool once) { - if (target.isEmpty()) { - qCCritical(logBare) << "Target required to listen for signals."; - return -1; - } else if (signal.isEmpty()) { - qCCritical(logBare) << "Signal required to listen."; - return -1; - } - - client->sendMessage(IpcCommand(SignalListenCommand {.target = target, .signal = signal})); - - while (true) { - SignalListenResponse slot; - if (!client->waitForResponse(slot)) return -1; - - if (std::holds_alternative(slot)) { - auto& result = std::get(slot); - QTextStream(stdout) << result.response << Qt::endl; - if (once) return 0; - else continue; - } else if (std::holds_alternative(slot)) { - qCCritical(logBare) << "Target not found."; - } else if (std::holds_alternative(slot)) { - qCCritical(logBare) << "Signal not found."; - } else if (std::holds_alternative(slot)) { - qCCritical(logBare) << "Not ready to accept queries yet."; - } else { - qCCritical(logIpc) << "Received invalid IPC response from" << client; - } - break; - } - - return -1; -} - -void SignalListenCommand::exec(qs::ipc::IpcServerConnection* conn) { - auto resp = conn->responseStream(); - - if (auto* generation = EngineGeneration::currentGeneration()) { - auto* registry = IpcHandlerRegistry::forGeneration(generation); - - auto* handler = registry->findHandler(this->target); - if (!handler) { - resp << TargetNotFound(); - return; - } - - auto* signal = handler->findSignal(this->signal); - if (!signal) { - resp << EntryNotFound(); - return; - } - - new RemoteSignalListener(conn, *this); - } else { - conn->respond(SignalListenResponse(NoCurrentGeneration())); - } -} - -RemoteSignalListener::RemoteSignalListener( - qs::ipc::IpcServerConnection* conn, - SignalListenCommand command -) - : conn(conn) - , command(std::move(command)) { - conn->setParent(this); - - QObject::connect( - IpcSignalRemoteListener::instance(), - &IpcSignalRemoteListener::triggered, - this, - &RemoteSignalListener::onSignal - ); - - QObject::connect( - conn, - &qs::ipc::IpcServerConnection::destroyed, - this, - &RemoteSignalListener::onConnDestroyed - ); - - qCDebug(logIpc) << "Remote listener created for" << this->command.target << this->command.signal - << ":" << this; -} - -RemoteSignalListener::~RemoteSignalListener() { - qCDebug(logIpc) << "Destroying remote listener" << this; -} - -void RemoteSignalListener::onSignal( - const QString& target, - const QString& signal, - const QString& value -) { - if (target != this->command.target || signal != this->command.signal) return; - qCDebug(logIpc) << "Remote signal" << signal << "triggered on" << target << "with value" << value; - - this->conn->respond(SignalListenResponse(SignalResponse {.response = value})); -} - -void RemoteSignalListener::onConnDestroyed() { this->deleteLater(); } - } // namespace qs::io::ipc::comm diff --git a/src/io/ipccomm.hpp b/src/io/ipccomm.hpp index ac12979..bc7dbf9 100644 --- a/src/io/ipccomm.hpp +++ b/src/io/ipccomm.hpp @@ -2,8 +2,6 @@ #include #include -#include -#include #include #include "../ipc/ipc.hpp" @@ -50,52 +48,4 @@ DEFINE_SIMPLE_DATASTREAM_OPS(StringPropReadCommand, data.target, data.property); int getProperty(qs::ipc::IpcClient* client, const QString& target, const QString& property); -struct SignalListenCommand { - QString target; - QString signal; - - void exec(qs::ipc::IpcServerConnection* conn); -}; - -DEFINE_SIMPLE_DATASTREAM_OPS(SignalListenCommand, data.target, data.signal); - -int listenToSignal( - qs::ipc::IpcClient* client, - const QString& target, - const QString& signal, - bool once -); - -struct NoCurrentGeneration: std::monostate {}; -struct TargetNotFound: std::monostate {}; -struct EntryNotFound: std::monostate {}; - -struct SignalResponse { - QString response; -}; - -DEFINE_SIMPLE_DATASTREAM_OPS(SignalResponse, data.response); - -using SignalListenResponse = std:: - variant; - -class RemoteSignalListener: public QObject { - Q_OBJECT; - -public: - explicit RemoteSignalListener(qs::ipc::IpcServerConnection* conn, SignalListenCommand command); - - ~RemoteSignalListener() override; - - Q_DISABLE_COPY_MOVE(RemoteSignalListener); - -private slots: - void onSignal(const QString& target, const QString& signal, const QString& value); - void onConnDestroyed(); - -private: - qs::ipc::IpcServerConnection* conn; - SignalListenCommand command; -}; - } // namespace qs::io::ipc::comm diff --git a/src/io/ipchandler.cpp b/src/io/ipchandler.cpp index e80cf4b..5ffa0ad 100644 --- a/src/io/ipchandler.cpp +++ b/src/io/ipchandler.cpp @@ -1,7 +1,5 @@ #include "ipchandler.hpp" #include -#include -#include #include #include @@ -141,75 +139,6 @@ WirePropertyDefinition IpcProperty::wireDef() const { return wire; } -WireSignalDefinition IpcSignal::wireDef() const { - WireSignalDefinition wire; - wire.name = this->signal.name(); - if (this->targetSlot != IpcSignalListener::SLOT_VOID) { - wire.retname = this->signal.parameterNames().value(0); - if (this->targetSlot == IpcSignalListener::SLOT_STRING) wire.rettype = "string"; - else if (this->targetSlot == IpcSignalListener::SLOT_INT) wire.rettype = "int"; - else if (this->targetSlot == IpcSignalListener::SLOT_BOOL) wire.rettype = "bool"; - else if (this->targetSlot == IpcSignalListener::SLOT_REAL) wire.rettype = "real"; - else if (this->targetSlot == IpcSignalListener::SLOT_COLOR) wire.rettype = "color"; - } - return wire; -} - -// NOLINTBEGIN (cppcoreguidelines-interfaces-global-init) -// clang-format off -const int IpcSignalListener::SLOT_VOID = IpcSignalListener::staticMetaObject.indexOfSlot("invokeVoid()"); -const int IpcSignalListener::SLOT_STRING = IpcSignalListener::staticMetaObject.indexOfSlot("invokeString(QString)"); -const int IpcSignalListener::SLOT_INT = IpcSignalListener::staticMetaObject.indexOfSlot("invokeInt(int)"); -const int IpcSignalListener::SLOT_BOOL = IpcSignalListener::staticMetaObject.indexOfSlot("invokeBool(bool)"); -const int IpcSignalListener::SLOT_REAL = IpcSignalListener::staticMetaObject.indexOfSlot("invokeReal(double)"); -const int IpcSignalListener::SLOT_COLOR = IpcSignalListener::staticMetaObject.indexOfSlot("invokeColor(QColor)"); -// clang-format on -// NOLINTEND - -bool IpcSignal::resolve(QString& error) { - if (this->signal.parameterCount() > 1) { - error = "Due to technical limitations, IPC signals can have at most one argument."; - return false; - } - - auto slot = IpcSignalListener::SLOT_VOID; - - if (this->signal.parameterCount() == 1) { - auto paramType = this->signal.parameterType(0); - if (paramType == QMetaType::QString) slot = IpcSignalListener::SLOT_STRING; - else if (paramType == QMetaType::Int) slot = IpcSignalListener::SLOT_INT; - else if (paramType == QMetaType::Bool) slot = IpcSignalListener::SLOT_BOOL; - else if (paramType == QMetaType::Double) slot = IpcSignalListener::SLOT_REAL; - else if (paramType == QMetaType::QColor) slot = IpcSignalListener::SLOT_COLOR; - else { - error = QString("Type of argument (%2: %3) cannot be used across IPC.") - .arg(this->signal.parameterNames().value(0)) - .arg(QMetaType(paramType).name()); - - return false; - } - } - - this->targetSlot = slot; - return true; -} - -void IpcSignal::connectListener(IpcHandler* handler) { - if (this->targetSlot == -1) { - qFatal() << "Tried to connect unresolved IPC signal"; - } - - this->listener = std::make_shared(this->signal.name()); - QMetaObject::connect(handler, this->signal.methodIndex(), this->listener.get(), this->targetSlot); - - QObject::connect( - this->listener.get(), - &IpcSignalListener::triggered, - handler, - &IpcHandler::onSignalTriggered - ); -} - IpcCallStorage::IpcCallStorage(const IpcFunction& function): returnSlot(function.returnType) { for (const auto& arg: function.argumentTypes) { this->argumentSlots.emplace_back(arg); @@ -243,28 +172,16 @@ void IpcHandler::onPostReload() { // which should handle inheritance on the qml side. for (auto i = smeta.methodCount(); i != meta->methodCount(); i++) { const auto& method = meta->method(i); - if (method.methodType() == QMetaMethod::Slot) { - auto ipcFunc = IpcFunction(method); - QString error; + if (method.methodType() != QMetaMethod::Slot) continue; - if (!ipcFunc.resolve(error)) { - qmlWarning(this).nospace().noquote() - << "Error parsing function \"" << method.name() << "\": " << error; - } else { - this->functionMap.insert(method.name(), ipcFunc); - } - } else if (method.methodType() == QMetaMethod::Signal) { - qmlDebug(this) << "Signal detected: " << method.name(); - auto ipcSig = IpcSignal(method); - QString error; + auto ipcFunc = IpcFunction(method); + QString error; - if (!ipcSig.resolve(error)) { - qmlWarning(this).nospace().noquote() - << "Error parsing signal \"" << method.name() << "\": " << error; - } else { - ipcSig.connectListener(this); - this->signalMap.emplace(method.name(), std::move(ipcSig)); - } + if (!ipcFunc.resolve(error)) { + qmlWarning(this).nospace().noquote() + << "Error parsing function \"" << method.name() << "\": " << error; + } else { + this->functionMap.insert(method.name(), ipcFunc); } } @@ -305,11 +222,6 @@ IpcHandlerRegistry* IpcHandlerRegistry::forGeneration(EngineGeneration* generati return dynamic_cast(ext); } -void IpcHandler::onSignalTriggered(const QString& signal, const QString& value) const { - emit IpcSignalRemoteListener::instance() - -> triggered(this->registeredState.target, signal, value); -} - void IpcHandler::updateRegistration(bool destroying) { if (!this->complete) return; @@ -412,10 +324,6 @@ WireTargetDefinition IpcHandler::wireDef() const { wire.properties += prop.wireDef(); } - for (const auto& sig: this->signalMap.values()) { - wire.signalFunctions += sig.wireDef(); - } - return wire; } @@ -460,13 +368,6 @@ IpcProperty* IpcHandler::findProperty(const QString& name) { else return &*itr; } -IpcSignal* IpcHandler::findSignal(const QString& name) { - auto itr = this->signalMap.find(name); - - if (itr == this->signalMap.end()) return nullptr; - else return &*itr; -} - IpcHandler* IpcHandlerRegistry::findHandler(const QString& target) { return this->handlers.value(target); } @@ -481,9 +382,4 @@ QVector IpcHandlerRegistry::wireTargets() const { return wire; } -IpcSignalRemoteListener* IpcSignalRemoteListener::instance() { - static auto* instance = new IpcSignalRemoteListener(); - return instance; -} - } // namespace qs::io::ipc diff --git a/src/io/ipchandler.hpp b/src/io/ipchandler.hpp index eb274e3..4c5d9bc 100644 --- a/src/io/ipchandler.hpp +++ b/src/io/ipchandler.hpp @@ -1,10 +1,8 @@ #pragma once #include -#include #include -#include #include #include #include @@ -69,54 +67,6 @@ public: const IpcType* type = nullptr; }; -class IpcSignalListener: public QObject { - Q_OBJECT; - -public: - IpcSignalListener(QString signal): signal(std::move(signal)) {} - - static const int SLOT_VOID; - static const int SLOT_STRING; - static const int SLOT_INT; - static const int SLOT_BOOL; - static const int SLOT_REAL; - static const int SLOT_COLOR; - -signals: - void triggered(const QString& signal, const QString& value); - -private slots: - void invokeVoid() { this->triggered(this->signal, "void"); } - void invokeString(const QString& value) { this->triggered(this->signal, value); } - void invokeInt(int value) { this->triggered(this->signal, QString::number(value)); } - void invokeBool(bool value) { this->triggered(this->signal, value ? "true" : "false"); } - void invokeReal(double value) { this->triggered(this->signal, QString::number(value)); } - void invokeColor(QColor value) { this->triggered(this->signal, value.name(QColor::HexArgb)); } - -private: - QString signal; -}; - -class IpcHandler; - -class IpcSignal { -public: - explicit IpcSignal(QMetaMethod signal): signal(signal) {} - - bool resolve(QString& error); - - [[nodiscard]] WireSignalDefinition wireDef() const; - - QMetaMethod signal; - int targetSlot = -1; - - void connectListener(IpcHandler* handler); - -private: - void connectListener(QObject* handler, IpcSignalListener* listener) const; - std::shared_ptr listener; -}; - class IpcHandlerRegistry; ///! Handler for IPC message calls. @@ -150,11 +100,6 @@ class IpcHandlerRegistry; /// - `real` will be converted to a string and returned. /// - `color` will be converted to a hex string in the form `#AARRGGBB` and returned. /// -/// #### Signals -/// IPC handler signals can be observed remotely using `qs ipc wait` (one call) -/// and `qs ipc listen` (many calls). IPC signals may have zero or one argument, where -/// the argument is one of the types listed above, or no arguments for void. -/// /// #### Example /// The following example creates ipc functions to control and retrieve the appearance /// of a Rectangle. @@ -174,18 +119,10 @@ class IpcHandlerRegistry; /// /// function setColor(color: color): void { rect.color = color; } /// function getColor(): color { return rect.color; } -/// /// function setAngle(angle: real): void { rect.rotation = angle; } /// function getAngle(): real { return rect.rotation; } -/// -/// function setRadius(radius: int): void { -/// rect.radius = radius; -/// this.radiusChanged(radius); -/// } -/// +/// function setRadius(radius: int): void { rect.radius = radius; } /// function getRadius(): int { return rect.radius; } -/// -/// signal radiusChanged(newRadius: int); /// } /// } /// ``` @@ -199,7 +136,6 @@ class IpcHandlerRegistry; /// function getAngle(): real /// function setRadius(radius: int): void /// function getRadius(): int -/// signal radiusChanged(newRadius: int) /// ``` /// /// and then invoked using `qs ipc call`. @@ -243,15 +179,14 @@ public: QString listMembers(qsizetype indent); [[nodiscard]] IpcFunction* findFunction(const QString& name); [[nodiscard]] IpcProperty* findProperty(const QString& name); - [[nodiscard]] IpcSignal* findSignal(const QString& name); [[nodiscard]] WireTargetDefinition wireDef() const; signals: void enabledChanged(); void targetChanged(); -public slots: - void onSignalTriggered(const QString& signal, const QString& value) const; +private slots: + //void handleIpcPropertyChange(); private: void updateRegistration(bool destroying = false); @@ -269,7 +204,6 @@ private: QHash functionMap; QHash propertyMap; - QHash signalMap; friend class IpcHandlerRegistry; }; @@ -293,14 +227,4 @@ private: QHash> knownHandlers; }; -class IpcSignalRemoteListener: public QObject { - Q_OBJECT; - -public: - static IpcSignalRemoteListener* instance(); - -signals: - void triggered(const QString& target, const QString& signal, const QString& value); -}; - } // namespace qs::io::ipc diff --git a/src/ipc/ipc.cpp b/src/ipc/ipc.cpp index 32d8482..0196359 100644 --- a/src/ipc/ipc.cpp +++ b/src/ipc/ipc.cpp @@ -61,7 +61,6 @@ IpcServerConnection::IpcServerConnection(QLocalSocket* socket, IpcServer* server void IpcServerConnection::onDisconnected() { qCInfo(logIpc) << "IPC connection disconnected" << this; - delete this; } void IpcServerConnection::onReadyRead() { @@ -85,11 +84,6 @@ void IpcServerConnection::onReadyRead() { ); if (!this->stream.commitTransaction()) return; - - // async connections reparent - if (dynamic_cast(this->parent()) != nullptr) { - delete this; - } } IpcClient::IpcClient(const QString& path) { diff --git a/src/ipc/ipccommand.hpp b/src/ipc/ipccommand.hpp index 105ce1e..b221b46 100644 --- a/src/ipc/ipccommand.hpp +++ b/src/ipc/ipccommand.hpp @@ -16,7 +16,6 @@ using IpcCommand = std::variant< IpcKillCommand, qs::io::ipc::comm::QueryMetadataCommand, qs::io::ipc::comm::StringCallCommand, - qs::io::ipc::comm::SignalListenCommand, qs::io::ipc::comm::StringPropReadCommand>; } // namespace qs::ipc diff --git a/src/launch/command.cpp b/src/launch/command.cpp index 151fc24..1a58cb8 100644 --- a/src/launch/command.cpp +++ b/src/launch/command.cpp @@ -411,10 +411,6 @@ int ipcCommand(CommandState& cmd) { return qs::io::ipc::comm::queryMetadata(&client, *cmd.ipc.target, *cmd.ipc.name); } else if (*cmd.ipc.getprop) { return qs::io::ipc::comm::getProperty(&client, *cmd.ipc.target, *cmd.ipc.name); - } else if (*cmd.ipc.wait) { - return qs::io::ipc::comm::listenToSignal(&client, *cmd.ipc.target, *cmd.ipc.name, true); - } else if (*cmd.ipc.listen) { - return qs::io::ipc::comm::listenToSignal(&client, *cmd.ipc.target, *cmd.ipc.name, false); } else { QVector arguments; for (auto& arg: cmd.ipc.arguments) { @@ -519,8 +515,8 @@ int runCommand(int argc, char** argv, QCoreApplication* coreApplication) { } if (state.misc.printVersion) { - qCInfo(logBare).noquote().nospace() << "quickshell " << QS_VERSION << ", revision " - << GIT_REVISION << ", distributed by: " << DISTRIBUTOR; + qCInfo(logBare).noquote().nospace() + << "quickshell 0.2.1, revision " << GIT_REVISION << ", distributed by: " << DISTRIBUTOR; if (state.log.verbosity > 1) { qCInfo(logBare).noquote() << "\nBuildtime Qt Version:" << QT_VERSION_STR; diff --git a/src/launch/launch_p.hpp b/src/launch/launch_p.hpp index f666e7a..a186ddb 100644 --- a/src/launch/launch_p.hpp +++ b/src/launch/launch_p.hpp @@ -74,8 +74,6 @@ struct CommandState { CLI::App* show = nullptr; CLI::App* call = nullptr; CLI::App* getprop = nullptr; - CLI::App* wait = nullptr; - CLI::App* listen = nullptr; bool showOld = false; QStringOption target; QStringOption name; diff --git a/src/launch/parsecommand.cpp b/src/launch/parsecommand.cpp index fc43b6b..0776f58 100644 --- a/src/launch/parsecommand.cpp +++ b/src/launch/parsecommand.cpp @@ -1,7 +1,6 @@ #include #include #include -#include #include #include // NOLINT: Need to include this for impls of some CLI11 classes @@ -227,16 +226,6 @@ int parseCommand(int argc, char** argv, CommandState& state) { ->allow_extra_args(); } - auto signalCmd = [&](std::string cmd, std::string desc) { - auto* scmd = sub->add_subcommand(std::move(cmd), std::move(desc)); - scmd->add_option("target", state.ipc.target, "The target to listen on."); - scmd->add_option("signal", state.ipc.name, "The signal to listen for."); - return scmd; - }; - - state.ipc.wait = signalCmd("wait", "Wait for one IpcHandler signal."); - state.ipc.listen = signalCmd("listen", "Listen for IpcHandler signals."); - { auto* prop = sub->add_subcommand("prop", "Manipulate IpcHandler properties.")->require_subcommand();