forked from quickshell/quickshell
io/ipchandler: add prop get
This commit is contained in:
parent
9417d6fa57
commit
4f2610dece
|
@ -1,9 +1,12 @@
|
|||
#include "ipc.hpp"
|
||||
#include <cstring>
|
||||
#include <utility>
|
||||
|
||||
#include <qcolor.h>
|
||||
#include <qmetatype.h>
|
||||
#include <qobjectdefs.h>
|
||||
#include <qtypes.h>
|
||||
#include <qvariant.h>
|
||||
|
||||
namespace qs::io::ipc {
|
||||
|
||||
|
@ -14,6 +17,12 @@ const BoolIpcType BoolIpcType::INSTANCE {};
|
|||
const DoubleIpcType DoubleIpcType::INSTANCE {};
|
||||
const ColorIpcType ColorIpcType::INSTANCE {};
|
||||
|
||||
void* IpcType::copyStorage(const void* data) const {
|
||||
auto* storage = this->createStorage();
|
||||
memcpy(storage, data, this->size());
|
||||
return storage;
|
||||
}
|
||||
|
||||
const IpcType* IpcType::ipcType(const QMetaType& metaType) {
|
||||
if (metaType.id() == QMetaType::Void) return &VoidIpcType::INSTANCE;
|
||||
if (metaType.id() == QMetaType::QString) return &StringIpcType::INSTANCE;
|
||||
|
@ -70,12 +79,18 @@ void IpcTypeSlot::replace(void* value) {
|
|||
this->storage = value;
|
||||
}
|
||||
|
||||
void IpcTypeSlot::replace(const QVariant& value) {
|
||||
this->replace(this->mType->copyStorage(value.constData()));
|
||||
}
|
||||
|
||||
const char* VoidIpcType::name() const { return "void"; }
|
||||
const char* VoidIpcType::genericArgumentName() const { return "void"; }
|
||||
qsizetype VoidIpcType::size() const { return 0; }
|
||||
|
||||
// string
|
||||
const char* StringIpcType::name() const { return "string"; }
|
||||
const char* StringIpcType::genericArgumentName() const { return "QString"; }
|
||||
qsizetype StringIpcType::size() const { return sizeof(QString); }
|
||||
void* StringIpcType::fromString(const QString& string) const { return new QString(string); }
|
||||
QString StringIpcType::toString(void* slot) const { return *static_cast<QString*>(slot); }
|
||||
void* StringIpcType::createStorage() const { return new QString(); }
|
||||
|
@ -84,6 +99,7 @@ void StringIpcType::destroyStorage(void* slot) const { delete static_cast<QStrin
|
|||
// int
|
||||
const char* IntIpcType::name() const { return "int"; }
|
||||
const char* IntIpcType::genericArgumentName() const { return "int"; }
|
||||
qsizetype IntIpcType::size() const { return sizeof(int); }
|
||||
|
||||
void* IntIpcType::fromString(const QString& string) const {
|
||||
auto ok = false;
|
||||
|
@ -100,6 +116,7 @@ void IntIpcType::destroyStorage(void* slot) const { delete static_cast<int*>(slo
|
|||
// bool
|
||||
const char* BoolIpcType::name() const { return "bool"; }
|
||||
const char* BoolIpcType::genericArgumentName() const { return "bool"; }
|
||||
qsizetype BoolIpcType::size() const { return sizeof(bool); }
|
||||
|
||||
void* BoolIpcType::fromString(const QString& string) const {
|
||||
if (string == "true") return new bool(true);
|
||||
|
@ -121,6 +138,7 @@ void BoolIpcType::destroyStorage(void* slot) const { delete static_cast<bool*>(s
|
|||
// double
|
||||
const char* DoubleIpcType::name() const { return "real"; }
|
||||
const char* DoubleIpcType::genericArgumentName() const { return "double"; }
|
||||
qsizetype DoubleIpcType::size() const { return sizeof(double); }
|
||||
|
||||
void* DoubleIpcType::fromString(const QString& string) const {
|
||||
auto ok = false;
|
||||
|
@ -139,6 +157,7 @@ void DoubleIpcType::destroyStorage(void* slot) const { delete static_cast<double
|
|||
// color
|
||||
const char* ColorIpcType::name() const { return "color"; }
|
||||
const char* ColorIpcType::genericArgumentName() const { return "QColor"; }
|
||||
qsizetype ColorIpcType::size() const { return sizeof(QColor); }
|
||||
|
||||
void* ColorIpcType::fromString(const QString& string) const {
|
||||
auto color = QColor::fromString(string);
|
||||
|
@ -167,6 +186,10 @@ QString WireFunctionDefinition::toString() const {
|
|||
return "function " % this->name % '(' % paramString % "): " % this->returnType;
|
||||
}
|
||||
|
||||
QString WirePropertyDefinition::toString() const {
|
||||
return "property " % this->name % ": " % this->type;
|
||||
}
|
||||
|
||||
QString WireTargetDefinition::toString() const {
|
||||
QString accum = "target " % this->name;
|
||||
|
||||
|
@ -174,6 +197,10 @@ QString WireTargetDefinition::toString() const {
|
|||
accum += "\n " % func.toString();
|
||||
}
|
||||
|
||||
for (const auto& prop: this->properties) {
|
||||
accum += "\n " % prop.toString();
|
||||
}
|
||||
|
||||
return accum;
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include <qcontainerfwd.h>
|
||||
#include <qobjectdefs.h>
|
||||
#include <qtclasshelpermacros.h>
|
||||
#include <qtypes.h>
|
||||
|
||||
#include "../ipc/ipc.hpp"
|
||||
|
||||
|
@ -21,10 +22,12 @@ public:
|
|||
|
||||
[[nodiscard]] virtual const char* name() const = 0;
|
||||
[[nodiscard]] virtual const char* genericArgumentName() const = 0;
|
||||
[[nodiscard]] virtual qsizetype size() const = 0;
|
||||
[[nodiscard]] virtual void* fromString(const QString& /*string*/) const { return nullptr; }
|
||||
[[nodiscard]] virtual QString toString(void* /*slot*/) const { return ""; }
|
||||
[[nodiscard]] virtual void* createStorage() const { return nullptr; }
|
||||
virtual void destroyStorage(void* /*slot*/) const {}
|
||||
void* copyStorage(const void* data) const;
|
||||
|
||||
static const IpcType* ipcType(const QMetaType& metaType);
|
||||
};
|
||||
|
@ -43,6 +46,7 @@ public:
|
|||
[[nodiscard]] QGenericReturnArgument asGenericReturnArgument();
|
||||
|
||||
void replace(void* value);
|
||||
void replace(const QVariant& value);
|
||||
|
||||
private:
|
||||
const IpcType* mType = nullptr;
|
||||
|
@ -53,6 +57,7 @@ class VoidIpcType: public IpcType {
|
|||
public:
|
||||
[[nodiscard]] const char* name() const override;
|
||||
[[nodiscard]] const char* genericArgumentName() const override;
|
||||
[[nodiscard]] qsizetype size() const override;
|
||||
|
||||
static const VoidIpcType INSTANCE;
|
||||
};
|
||||
|
@ -61,6 +66,7 @@ class StringIpcType: public IpcType {
|
|||
public:
|
||||
[[nodiscard]] const char* name() const override;
|
||||
[[nodiscard]] const char* genericArgumentName() const override;
|
||||
[[nodiscard]] qsizetype size() const override;
|
||||
[[nodiscard]] void* fromString(const QString& string) const override;
|
||||
[[nodiscard]] QString toString(void* slot) const override;
|
||||
[[nodiscard]] void* createStorage() const override;
|
||||
|
@ -73,6 +79,7 @@ class IntIpcType: public IpcType {
|
|||
public:
|
||||
[[nodiscard]] const char* name() const override;
|
||||
[[nodiscard]] const char* genericArgumentName() const override;
|
||||
[[nodiscard]] qsizetype size() const override;
|
||||
[[nodiscard]] void* fromString(const QString& string) const override;
|
||||
[[nodiscard]] QString toString(void* slot) const override;
|
||||
[[nodiscard]] void* createStorage() const override;
|
||||
|
@ -85,6 +92,7 @@ class BoolIpcType: public IpcType {
|
|||
public:
|
||||
[[nodiscard]] const char* name() const override;
|
||||
[[nodiscard]] const char* genericArgumentName() const override;
|
||||
[[nodiscard]] qsizetype size() const override;
|
||||
[[nodiscard]] void* fromString(const QString& string) const override;
|
||||
[[nodiscard]] QString toString(void* slot) const override;
|
||||
[[nodiscard]] void* createStorage() const override;
|
||||
|
@ -97,6 +105,7 @@ class DoubleIpcType: public IpcType {
|
|||
public:
|
||||
[[nodiscard]] const char* name() const override;
|
||||
[[nodiscard]] const char* genericArgumentName() const override;
|
||||
[[nodiscard]] qsizetype size() const override;
|
||||
[[nodiscard]] void* fromString(const QString& string) const override;
|
||||
[[nodiscard]] QString toString(void* slot) const override;
|
||||
[[nodiscard]] void* createStorage() const override;
|
||||
|
@ -109,6 +118,7 @@ class ColorIpcType: public IpcType {
|
|||
public:
|
||||
[[nodiscard]] const char* name() const override;
|
||||
[[nodiscard]] const char* genericArgumentName() const override;
|
||||
[[nodiscard]] qsizetype size() const override;
|
||||
[[nodiscard]] void* fromString(const QString& string) const override;
|
||||
[[nodiscard]] QString toString(void* slot) const override;
|
||||
[[nodiscard]] void* createStorage() const override;
|
||||
|
@ -127,13 +137,23 @@ struct WireFunctionDefinition {
|
|||
|
||||
DEFINE_SIMPLE_DATASTREAM_OPS(WireFunctionDefinition, data.name, data.returnType, data.arguments);
|
||||
|
||||
struct WireTargetDefinition {
|
||||
struct WirePropertyDefinition {
|
||||
QString name;
|
||||
QVector<WireFunctionDefinition> functions;
|
||||
QString type;
|
||||
|
||||
[[nodiscard]] QString toString() const;
|
||||
};
|
||||
|
||||
DEFINE_SIMPLE_DATASTREAM_OPS(WireTargetDefinition, data.name, data.functions);
|
||||
DEFINE_SIMPLE_DATASTREAM_OPS(WirePropertyDefinition, data.name, data.type);
|
||||
|
||||
struct WireTargetDefinition {
|
||||
QString name;
|
||||
QVector<WireFunctionDefinition> functions;
|
||||
QVector<WirePropertyDefinition> properties;
|
||||
|
||||
[[nodiscard]] QString toString() const;
|
||||
};
|
||||
|
||||
DEFINE_SIMPLE_DATASTREAM_OPS(WireTargetDefinition, data.name, data.functions, data.properties);
|
||||
|
||||
} // namespace qs::io::ipc
|
||||
|
|
|
@ -21,16 +21,17 @@ namespace qs::io::ipc::comm {
|
|||
|
||||
struct NoCurrentGeneration: std::monostate {};
|
||||
struct TargetNotFound: std::monostate {};
|
||||
struct FunctionNotFound: std::monostate {};
|
||||
struct EntryNotFound: std::monostate {};
|
||||
|
||||
using QueryResponse = std::variant<
|
||||
std::monostate,
|
||||
NoCurrentGeneration,
|
||||
TargetNotFound,
|
||||
FunctionNotFound,
|
||||
EntryNotFound,
|
||||
QVector<WireTargetDefinition>,
|
||||
WireTargetDefinition,
|
||||
WireFunctionDefinition>;
|
||||
WireFunctionDefinition,
|
||||
WirePropertyDefinition>;
|
||||
|
||||
void QueryMetadataCommand::exec(qs::ipc::IpcServerConnection* conn) const {
|
||||
auto resp = conn->responseStream<QueryResponse>();
|
||||
|
@ -44,16 +45,24 @@ void QueryMetadataCommand::exec(qs::ipc::IpcServerConnection* conn) const {
|
|||
auto* handler = registry->findHandler(this->target);
|
||||
|
||||
if (handler) {
|
||||
if (this->function.isEmpty()) {
|
||||
if (this->name.isEmpty()) {
|
||||
resp << handler->wireDef();
|
||||
} else {
|
||||
auto* func = handler->findFunction(this->function);
|
||||
auto* func = handler->findFunction(this->name);
|
||||
|
||||
if (func) {
|
||||
resp << func->wireDef();
|
||||
} else {
|
||||
resp << FunctionNotFound();
|
||||
return;
|
||||
}
|
||||
|
||||
auto* prop = handler->findProperty(this->name);
|
||||
|
||||
if (prop) {
|
||||
resp << prop->wireDef();
|
||||
return;
|
||||
}
|
||||
|
||||
resp << EntryNotFound();
|
||||
}
|
||||
} else {
|
||||
resp << TargetNotFound();
|
||||
|
@ -64,8 +73,8 @@ void QueryMetadataCommand::exec(qs::ipc::IpcServerConnection* conn) const {
|
|||
}
|
||||
}
|
||||
|
||||
int queryMetadata(IpcClient* client, const QString& target, const QString& function) {
|
||||
client->sendMessage(IpcCommand(QueryMetadataCommand {.target = target, .function = function}));
|
||||
int queryMetadata(IpcClient* client, const QString& target, const QString& name) {
|
||||
client->sendMessage(IpcCommand(QueryMetadataCommand {.target = target, .name = name}));
|
||||
|
||||
QueryResponse slot;
|
||||
if (!client->waitForResponse(slot)) return -1;
|
||||
|
@ -82,9 +91,11 @@ int queryMetadata(IpcClient* client, const QString& target, const QString& funct
|
|||
qCInfo(logBare).noquote() << std::get<WireTargetDefinition>(slot).toString();
|
||||
} else if (std::holds_alternative<WireFunctionDefinition>(slot)) {
|
||||
qCInfo(logBare).noquote() << std::get<WireFunctionDefinition>(slot).toString();
|
||||
} else if (std::holds_alternative<WirePropertyDefinition>(slot)) {
|
||||
qCInfo(logBare).noquote() << std::get<WirePropertyDefinition>(slot).toString();
|
||||
} else if (std::holds_alternative<TargetNotFound>(slot)) {
|
||||
qCCritical(logBare) << "Target not found.";
|
||||
} else if (std::holds_alternative<FunctionNotFound>(slot)) {
|
||||
} else if (std::holds_alternative<EntryNotFound>(slot)) {
|
||||
qCCritical(logBare) << "Function not found.";
|
||||
} else if (std::holds_alternative<NoCurrentGeneration>(slot)) {
|
||||
qCCritical(logBare) << "Not ready to accept queries yet.";
|
||||
|
@ -119,7 +130,7 @@ using StringCallResponse = std::variant<
|
|||
std::monostate,
|
||||
NoCurrentGeneration,
|
||||
TargetNotFound,
|
||||
FunctionNotFound,
|
||||
EntryNotFound,
|
||||
ArgParseFailed,
|
||||
Completed>;
|
||||
|
||||
|
@ -137,7 +148,7 @@ void StringCallCommand::exec(qs::ipc::IpcServerConnection* conn) const {
|
|||
|
||||
auto* func = handler->findFunction(this->function);
|
||||
if (!func) {
|
||||
resp << FunctionNotFound();
|
||||
resp << EntryNotFound();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -223,7 +234,7 @@ int callFunction(
|
|||
qCCritical(logBare).noquote() << "Function definition:" << error.definition.toString();
|
||||
} else if (std::holds_alternative<TargetNotFound>(slot)) {
|
||||
qCCritical(logBare) << "Target not found.";
|
||||
} else if (std::holds_alternative<FunctionNotFound>(slot)) {
|
||||
} else if (std::holds_alternative<EntryNotFound>(slot)) {
|
||||
qCCritical(logBare) << "Function not found.";
|
||||
} else if (std::holds_alternative<NoCurrentGeneration>(slot)) {
|
||||
qCCritical(logBare) << "Not ready to accept queries yet.";
|
||||
|
@ -233,4 +244,74 @@ int callFunction(
|
|||
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct PropertyValue {
|
||||
QString value;
|
||||
};
|
||||
|
||||
DEFINE_SIMPLE_DATASTREAM_OPS(PropertyValue, data.value);
|
||||
|
||||
using StringPropReadResponse =
|
||||
std::variant<std::monostate, NoCurrentGeneration, TargetNotFound, EntryNotFound, PropertyValue>;
|
||||
|
||||
void StringPropReadCommand::exec(qs::ipc::IpcServerConnection* conn) const {
|
||||
auto resp = conn->responseStream<StringPropReadResponse>();
|
||||
|
||||
if (auto* generation = EngineGeneration::currentGeneration()) {
|
||||
auto* registry = IpcHandlerRegistry::forGeneration(generation);
|
||||
|
||||
auto* handler = registry->findHandler(this->target);
|
||||
if (!handler) {
|
||||
resp << TargetNotFound();
|
||||
return;
|
||||
}
|
||||
|
||||
auto* prop = handler->findProperty(this->property);
|
||||
if (!prop) {
|
||||
resp << EntryNotFound();
|
||||
return;
|
||||
}
|
||||
|
||||
auto slot = IpcTypeSlot(prop->type);
|
||||
prop->read(handler, slot);
|
||||
|
||||
resp << PropertyValue {
|
||||
.value = slot.type()->toString(slot.get()),
|
||||
};
|
||||
} else {
|
||||
conn->respond(StringCallResponse(NoCurrentGeneration()));
|
||||
}
|
||||
}
|
||||
|
||||
int getProperty(IpcClient* client, const QString& target, const QString& property) {
|
||||
if (target.isEmpty()) {
|
||||
qCCritical(logBare) << "Target required to send message.";
|
||||
return -1;
|
||||
} else if (property.isEmpty()) {
|
||||
qCCritical(logBare) << "Property required to send message.";
|
||||
return -1;
|
||||
}
|
||||
|
||||
client->sendMessage(IpcCommand(StringPropReadCommand {.target = target, .property = property}));
|
||||
|
||||
StringPropReadResponse slot;
|
||||
if (!client->waitForResponse(slot)) return -1;
|
||||
|
||||
if (std::holds_alternative<PropertyValue>(slot)) {
|
||||
auto& result = std::get<PropertyValue>(slot);
|
||||
QTextStream(stdout) << result.value << Qt::endl;
|
||||
return 0;
|
||||
} else if (std::holds_alternative<TargetNotFound>(slot)) {
|
||||
qCCritical(logBare) << "Target not found.";
|
||||
} else if (std::holds_alternative<EntryNotFound>(slot)) {
|
||||
qCCritical(logBare) << "Property not found.";
|
||||
} else if (std::holds_alternative<NoCurrentGeneration>(slot)) {
|
||||
qCCritical(logBare) << "Not ready to accept queries yet.";
|
||||
} else {
|
||||
qCCritical(logIpc) << "Received invalid IPC response from" << client;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
} // namespace qs::io::ipc::comm
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include <qcontainerfwd.h>
|
||||
#include <qflags.h>
|
||||
#include <qtypes.h>
|
||||
|
||||
#include "../ipc/ipc.hpp"
|
||||
|
||||
|
@ -9,12 +10,12 @@ namespace qs::io::ipc::comm {
|
|||
|
||||
struct QueryMetadataCommand {
|
||||
QString target;
|
||||
QString function;
|
||||
QString name;
|
||||
|
||||
void exec(qs::ipc::IpcServerConnection* conn) const;
|
||||
};
|
||||
|
||||
DEFINE_SIMPLE_DATASTREAM_OPS(QueryMetadataCommand, data.target, data.function);
|
||||
DEFINE_SIMPLE_DATASTREAM_OPS(QueryMetadataCommand, data.target, data.name);
|
||||
|
||||
struct StringCallCommand {
|
||||
QString target;
|
||||
|
@ -27,7 +28,7 @@ struct StringCallCommand {
|
|||
DEFINE_SIMPLE_DATASTREAM_OPS(StringCallCommand, data.target, data.function, data.arguments);
|
||||
|
||||
void handleMsg(qs::ipc::IpcServerConnection* conn);
|
||||
int queryMetadata(qs::ipc::IpcClient* client, const QString& target, const QString& function);
|
||||
int queryMetadata(qs::ipc::IpcClient* client, const QString& target, const QString& name);
|
||||
|
||||
int callFunction(
|
||||
qs::ipc::IpcClient* client,
|
||||
|
@ -36,4 +37,15 @@ int callFunction(
|
|||
const QVector<QString>& arguments
|
||||
);
|
||||
|
||||
struct StringPropReadCommand {
|
||||
QString target;
|
||||
QString property;
|
||||
|
||||
void exec(qs::ipc::IpcServerConnection* conn) const;
|
||||
};
|
||||
|
||||
DEFINE_SIMPLE_DATASTREAM_OPS(StringPropReadCommand, data.target, data.property);
|
||||
|
||||
int getProperty(qs::ipc::IpcClient* client, const QString& target, const QString& property);
|
||||
|
||||
} // namespace qs::io::ipc::comm
|
||||
|
|
|
@ -107,6 +107,32 @@ WireFunctionDefinition IpcFunction::wireDef() const {
|
|||
return wire;
|
||||
}
|
||||
|
||||
bool IpcProperty::resolve(QString& error) {
|
||||
this->type = IpcType::ipcType(this->property.metaType());
|
||||
|
||||
if (!this->type) {
|
||||
error = QString("Type %1 cannot be used across IPC.").arg(this->property.metaType().name());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void IpcProperty::read(QObject* target, IpcTypeSlot& slot) const {
|
||||
slot.replace(this->property.read(target));
|
||||
}
|
||||
|
||||
QString IpcProperty::toString() const {
|
||||
return QString("property ") % this->property.name() % ": " % this->type->name();
|
||||
}
|
||||
|
||||
WirePropertyDefinition IpcProperty::wireDef() const {
|
||||
WirePropertyDefinition wire;
|
||||
wire.name = this->property.name();
|
||||
wire.type = this->type->name();
|
||||
return wire;
|
||||
}
|
||||
|
||||
IpcCallStorage::IpcCallStorage(const IpcFunction& function): returnSlot(function.returnType) {
|
||||
for (const auto& arg: function.argumentTypes) {
|
||||
this->argumentSlots.emplace_back(arg);
|
||||
|
@ -153,6 +179,21 @@ void IpcHandler::onPostReload() {
|
|||
}
|
||||
}
|
||||
|
||||
for (auto i = smeta.propertyCount(); i != meta->propertyCount(); i++) {
|
||||
const auto& property = meta->property(i);
|
||||
if (!property.isReadable() || !property.hasNotifySignal()) continue;
|
||||
|
||||
auto ipcProp = IpcProperty(property);
|
||||
QString error;
|
||||
|
||||
if (!ipcProp.resolve(error)) {
|
||||
qmlWarning(this).nospace().noquote()
|
||||
<< "Error parsing property \"" << property.name() << "\": " << error;
|
||||
} else {
|
||||
this->propertyMap.insert(property.name(), ipcProp);
|
||||
}
|
||||
}
|
||||
|
||||
this->complete = true;
|
||||
this->updateRegistration();
|
||||
|
||||
|
@ -270,6 +311,10 @@ WireTargetDefinition IpcHandler::wireDef() const {
|
|||
wire.functions += func.wireDef();
|
||||
}
|
||||
|
||||
for (const auto& prop: this->propertyMap.values()) {
|
||||
wire.properties += prop.wireDef();
|
||||
}
|
||||
|
||||
return wire;
|
||||
}
|
||||
|
||||
|
@ -307,6 +352,13 @@ IpcFunction* IpcHandler::findFunction(const QString& name) {
|
|||
else return &*itr;
|
||||
}
|
||||
|
||||
IpcProperty* IpcHandler::findProperty(const QString& name) {
|
||||
auto itr = this->propertyMap.find(name);
|
||||
|
||||
if (itr == this->propertyMap.end()) return nullptr;
|
||||
else return &*itr;
|
||||
}
|
||||
|
||||
IpcHandler* IpcHandlerRegistry::findHandler(const QString& target) {
|
||||
return this->handlers.value(target);
|
||||
}
|
||||
|
|
|
@ -53,14 +53,28 @@ private:
|
|||
friend class IpcFunction;
|
||||
};
|
||||
|
||||
class IpcProperty {
|
||||
public:
|
||||
explicit IpcProperty(QMetaProperty property): property(property) {}
|
||||
|
||||
bool resolve(QString& error);
|
||||
void read(QObject* target, IpcTypeSlot& slot) const;
|
||||
|
||||
[[nodiscard]] QString toString() const;
|
||||
[[nodiscard]] WirePropertyDefinition wireDef() const;
|
||||
|
||||
QMetaProperty property;
|
||||
const IpcType* type = nullptr;
|
||||
};
|
||||
|
||||
class IpcHandlerRegistry;
|
||||
|
||||
///! Handler for IPC message calls.
|
||||
/// Each IpcHandler is registered into a per-instance map by its unique @@target.
|
||||
/// Functions defined on the IpcHandler can be called by `qs msg`.
|
||||
/// Functions and properties defined on the IpcHandler can be accessed via `qs ipc`.
|
||||
///
|
||||
/// #### Handler Functions
|
||||
/// IPC handler functions can be called by `qs msg` as long as they have at most 10
|
||||
/// IPC handler functions can be called by `qs ipc call` as long as they have at most 10
|
||||
/// arguments, and all argument types along with the return type are listed below.
|
||||
///
|
||||
/// **Argument and return types must be explicitly specified or they will not
|
||||
|
@ -112,9 +126,9 @@ class IpcHandlerRegistry;
|
|||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
/// The list of registered targets can be inspected using `qs msg -s`.
|
||||
/// The list of registered targets can be inspected using `qs ipc show`.
|
||||
/// ```sh
|
||||
/// $ qs msg -s
|
||||
/// $ qs ipc show
|
||||
/// target rect
|
||||
/// function setColor(color: color): void
|
||||
/// function getColor(): color
|
||||
|
@ -124,18 +138,22 @@ class IpcHandlerRegistry;
|
|||
/// function getRadius(): int
|
||||
/// ```
|
||||
///
|
||||
/// and then invoked using `qs msg`.
|
||||
/// and then invoked using `qs ipc call`.
|
||||
/// ```sh
|
||||
/// $ qs msg rect setColor orange
|
||||
/// $ qs msg rect setAngle 40.5
|
||||
/// $ qs msg rect setRadius 30
|
||||
/// $ qs msg rect getColor
|
||||
/// $ qs ipc call rect setColor orange
|
||||
/// $ qs ipc call rect setAngle 40.5
|
||||
/// $ qs ipc call rect setRadius 30
|
||||
/// $ qs ipc call rect getColor
|
||||
/// #ffffa500
|
||||
/// $ qs msg rect getAngle
|
||||
/// $ qs ipc call rect getAngle
|
||||
/// 40.5
|
||||
/// $ qs msg rect getRadius
|
||||
/// $ qs ipc call rect getRadius
|
||||
/// 30
|
||||
/// ```
|
||||
///
|
||||
/// #### Properties
|
||||
/// Properties of an IpcHanlder can be read using `qs ipc prop get` as long as they are
|
||||
/// of an IPC compatible type. See the table above for compatible types.
|
||||
class IpcHandler
|
||||
: public QObject
|
||||
, public PostReloadHook {
|
||||
|
@ -162,12 +180,16 @@ public:
|
|||
|
||||
QString listMembers(qsizetype indent);
|
||||
[[nodiscard]] IpcFunction* findFunction(const QString& name);
|
||||
[[nodiscard]] IpcProperty* findProperty(const QString& name);
|
||||
[[nodiscard]] WireTargetDefinition wireDef() const;
|
||||
|
||||
signals:
|
||||
void enabledChanged();
|
||||
void targetChanged();
|
||||
|
||||
private slots:
|
||||
//void handleIpcPropertyChange();
|
||||
|
||||
private:
|
||||
void updateRegistration(bool destroying = false);
|
||||
|
||||
|
@ -183,6 +205,7 @@ private:
|
|||
bool complete = false;
|
||||
|
||||
QHash<QString, IpcFunction> functionMap;
|
||||
QHash<QString, IpcProperty> propertyMap;
|
||||
|
||||
friend class IpcHandlerRegistry;
|
||||
};
|
||||
|
|
|
@ -15,6 +15,7 @@ using IpcCommand = std::variant<
|
|||
std::monostate,
|
||||
IpcKillCommand,
|
||||
qs::io::ipc::comm::QueryMetadataCommand,
|
||||
qs::io::ipc::comm::StringCallCommand>;
|
||||
qs::io::ipc::comm::StringCallCommand,
|
||||
qs::io::ipc::comm::StringPropReadCommand>;
|
||||
|
||||
} // namespace qs::ipc
|
||||
|
|
|
@ -293,6 +293,8 @@ int ipcCommand(CommandState& cmd) {
|
|||
return IpcClient::connect(instance.instance.instanceId, [&](IpcClient& client) {
|
||||
if (*cmd.ipc.show || cmd.ipc.showOld) {
|
||||
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 {
|
||||
QVector<QString> arguments;
|
||||
for (auto& arg: cmd.ipc.arguments) {
|
||||
|
|
|
@ -71,6 +71,7 @@ struct CommandState {
|
|||
CLI::App* ipc = nullptr;
|
||||
CLI::App* show = nullptr;
|
||||
CLI::App* call = nullptr;
|
||||
CLI::App* getprop = nullptr;
|
||||
bool showOld = false;
|
||||
QStringOption target;
|
||||
QStringOption name;
|
||||
|
|
|
@ -194,6 +194,18 @@ int parseCommand(int argc, char** argv, CommandState& state) {
|
|||
->description("Arguments to the called function.")
|
||||
->allow_extra_args();
|
||||
}
|
||||
|
||||
{
|
||||
auto* prop =
|
||||
sub->add_subcommand("prop", "Manipulate IpcHandler properties.")->require_subcommand();
|
||||
|
||||
{
|
||||
auto* get = prop->add_subcommand("get", "Read the value of a property.");
|
||||
state.ipc.getprop = get;
|
||||
get->add_option("target", state.ipc.target, "The target to read the property of.");
|
||||
get->add_option("property", state.ipc.name)->description("The property to read.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue