mirror of
https://git.outfoxxed.me/quickshell/quickshell.git
synced 2026-02-23 03:33:57 +11:00
Some checks failed
Build / Nix (push) Has been cancelled
Build / Nix-1 (push) Has been cancelled
Build / Nix-2 (push) Has been cancelled
Build / Nix-3 (push) Has been cancelled
Build / Nix-4 (push) Has been cancelled
Build / Nix-5 (push) Has been cancelled
Build / Nix-6 (push) Has been cancelled
Build / Nix-7 (push) Has been cancelled
Build / Nix-8 (push) Has been cancelled
Build / Nix-9 (push) Has been cancelled
Build / Nix-10 (push) Has been cancelled
Build / Nix-11 (push) Has been cancelled
Build / Nix-12 (push) Has been cancelled
Build / Nix-13 (push) Has been cancelled
Build / Nix-14 (push) Has been cancelled
Build / Nix-15 (push) Has been cancelled
Build / Nix-16 (push) Has been cancelled
Build / Nix-17 (push) Has been cancelled
Build / Nix-18 (push) Has been cancelled
Build / Nix-19 (push) Has been cancelled
Build / Nix-20 (push) Has been cancelled
Build / Nix-21 (push) Has been cancelled
Build / Nix-22 (push) Has been cancelled
Build / Nix-23 (push) Has been cancelled
Build / Nix-24 (push) Has been cancelled
Build / Nix-25 (push) Has been cancelled
Build / Nix-26 (push) Has been cancelled
Build / Nix-27 (push) Has been cancelled
Build / Nix-28 (push) Has been cancelled
Build / Nix-29 (push) Has been cancelled
Build / Nix-30 (push) Has been cancelled
Build / Nix-31 (push) Has been cancelled
Build / Nix-32 (push) Has been cancelled
Build / Nix-33 (push) Has been cancelled
Build / Archlinux (push) Has been cancelled
Lint / Lint (push) Has been cancelled
306 lines
8.6 KiB
C++
306 lines
8.6 KiB
C++
#pragma once
|
|
|
|
#include <cstddef>
|
|
#include <memory>
|
|
#include <vector>
|
|
|
|
#include <qcolor.h>
|
|
#include <qcontainerfwd.h>
|
|
#include <qdebug.h>
|
|
#include <qhash.h>
|
|
#include <qmetaobject.h>
|
|
#include <qobject.h>
|
|
#include <qobjectdefs.h>
|
|
#include <qqmlintegration.h>
|
|
#include <qqmlparserstatus.h>
|
|
#include <qtclasshelpermacros.h>
|
|
#include <qtmetamacros.h>
|
|
#include <qtypes.h>
|
|
#include <qvariant.h>
|
|
|
|
#include "../core/generation.hpp"
|
|
#include "../core/reload.hpp"
|
|
#include "ipc.hpp"
|
|
|
|
namespace qs::io::ipc {
|
|
|
|
class IpcCallStorage;
|
|
|
|
class IpcFunction {
|
|
public:
|
|
explicit IpcFunction(QMetaMethod method): method(method) {}
|
|
|
|
bool resolve(QString& error);
|
|
void invoke(QObject* target, IpcCallStorage& storage) const;
|
|
|
|
[[nodiscard]] QString toString() const;
|
|
[[nodiscard]] WireFunctionDefinition wireDef() const;
|
|
|
|
QMetaMethod method;
|
|
QVector<const IpcType*> argumentTypes;
|
|
const IpcType* returnType = nullptr;
|
|
};
|
|
|
|
class IpcCallStorage {
|
|
public:
|
|
explicit IpcCallStorage(const IpcFunction& function);
|
|
|
|
bool setArgumentStr(size_t i, const QString& value);
|
|
[[nodiscard]] QString getReturnStr();
|
|
|
|
private:
|
|
std::vector<IpcTypeSlot> argumentSlots;
|
|
IpcTypeSlot returnSlot;
|
|
|
|
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 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<IpcSignalListener> listener;
|
|
};
|
|
|
|
class IpcHandlerRegistry;
|
|
|
|
///! Handler for IPC message calls.
|
|
/// Each IpcHandler is registered into a per-instance map by its unique @@target.
|
|
/// Functions and properties defined on the IpcHandler can be accessed via `qs ipc`.
|
|
///
|
|
/// #### Handler Functions
|
|
/// 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
|
|
/// be registered.**
|
|
///
|
|
/// ##### Arguments
|
|
/// - `string` will be passed to the parameter as is.
|
|
/// - `int` will only accept parameters that can be parsed as an integer.
|
|
/// - `bool` will only accept parameters that are "true", "false", or an integer,
|
|
/// where 0 will be converted to false, and anything else to true.
|
|
/// - `real` will only accept parameters that can be parsed as a number with
|
|
/// or without a decimal.
|
|
/// - `color` will accept [named colors] or hex strings (RGB, RRGGBB, AARRGGBB) with
|
|
/// an optional `#` prefix.
|
|
///
|
|
/// [named colors]: https://doc.qt.io/qt-6/qml-color.html#svg-color-reference
|
|
///
|
|
/// ##### Return Type
|
|
/// - `void` will return nothing.
|
|
/// - `string` will be returned as is.
|
|
/// - `int` will be converted to a string and returned.
|
|
/// - `bool` will be converted to "true" or "false" and returned.
|
|
/// - `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.
|
|
///
|
|
/// ```qml
|
|
/// FloatingWindow {
|
|
/// Rectangle {
|
|
/// id: rect
|
|
/// anchors.centerIn: parent
|
|
/// width: 100
|
|
/// height: 100
|
|
/// color: "red"
|
|
/// }
|
|
///
|
|
/// IpcHandler {
|
|
/// target: "rect"
|
|
///
|
|
/// 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 getRadius(): int { return rect.radius; }
|
|
///
|
|
/// signal radiusChanged(newRadius: int);
|
|
/// }
|
|
/// }
|
|
/// ```
|
|
/// The list of registered targets can be inspected using `qs ipc show`.
|
|
/// ```sh
|
|
/// $ qs ipc show
|
|
/// target rect
|
|
/// function setColor(color: color): void
|
|
/// function getColor(): color
|
|
/// function setAngle(angle: real): void
|
|
/// function getAngle(): real
|
|
/// function setRadius(radius: int): void
|
|
/// function getRadius(): int
|
|
/// signal radiusChanged(newRadius: int)
|
|
/// ```
|
|
///
|
|
/// and then invoked using `qs ipc call`.
|
|
/// ```sh
|
|
/// $ 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 ipc call rect getAngle
|
|
/// 40.5
|
|
/// $ 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 PostReloadHook {
|
|
Q_OBJECT;
|
|
/// If the handler should be able to receive calls. Defaults to true.
|
|
Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged);
|
|
/// The target this handler should be accessible from.
|
|
/// Required and must be unique. May be changed at runtime.
|
|
Q_PROPERTY(QString target READ target WRITE setTarget NOTIFY targetChanged);
|
|
QML_ELEMENT;
|
|
|
|
public:
|
|
explicit IpcHandler(QObject* parent = nullptr): PostReloadHook(parent) {}
|
|
~IpcHandler() override;
|
|
Q_DISABLE_COPY_MOVE(IpcHandler);
|
|
|
|
void onPostReload() override;
|
|
|
|
[[nodiscard]] bool enabled() const;
|
|
void setEnabled(bool enabled);
|
|
|
|
[[nodiscard]] QString target() const;
|
|
void setTarget(const QString& target);
|
|
|
|
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:
|
|
void updateRegistration(bool destroying = false);
|
|
|
|
struct RegistrationState {
|
|
explicit RegistrationState(bool enabled = false): enabled(enabled) {}
|
|
|
|
bool enabled = false;
|
|
QString target;
|
|
};
|
|
|
|
RegistrationState registeredState;
|
|
RegistrationState targetState {true};
|
|
bool complete = false;
|
|
|
|
QHash<QString, IpcFunction> functionMap;
|
|
QHash<QString, IpcProperty> propertyMap;
|
|
QHash<QString, IpcSignal> signalMap;
|
|
|
|
friend class IpcHandlerRegistry;
|
|
};
|
|
|
|
class IpcHandlerRegistry: public EngineGenerationExt {
|
|
public:
|
|
static IpcHandlerRegistry* forGeneration(EngineGeneration* generation);
|
|
|
|
void registerHandler(IpcHandler* handler);
|
|
void deregisterHandler(IpcHandler* handler);
|
|
|
|
QString listMembers(const QString& target, qsizetype indent);
|
|
QString listTargets(qsizetype indent);
|
|
|
|
IpcHandler* findHandler(const QString& target);
|
|
|
|
[[nodiscard]] QVector<WireTargetDefinition> wireTargets() const;
|
|
|
|
private:
|
|
QHash<QString, IpcHandler*> handlers;
|
|
QHash<QString, QVector<IpcHandler*>> 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
|