#pragma once #include #include #include #include #include #include #include #include #include "../../../core/model.hpp" #include "../../../core/qmlscreen.hpp" namespace qs::hyprland::ipc { class HyprlandMonitor; class HyprlandWorkspace; } // namespace qs::hyprland::ipc Q_DECLARE_OPAQUE_POINTER(qs::hyprland::ipc::HyprlandWorkspace*); Q_DECLARE_OPAQUE_POINTER(qs::hyprland::ipc::HyprlandMonitor*); namespace qs::hyprland::ipc { ///! Live Hyprland IPC event. /// Live Hyprland IPC event. Holding this object after the /// signal handler exits is undefined as the event instance /// is reused. /// /// Emitted by @@Hyprland.rawEvent(s). class HyprlandIpcEvent: public QObject { Q_OBJECT; /// The name of the event. /// /// See [Hyprland Wiki: IPC](https://wiki.hyprland.org/IPC/) for a list of events. Q_PROPERTY(QString name READ nameStr CONSTANT); /// The unparsed data of the event. Q_PROPERTY(QString data READ dataStr CONSTANT); QML_NAMED_ELEMENT(HyprlandEvent); QML_UNCREATABLE("HyprlandIpcEvents cannot be created."); public: HyprlandIpcEvent(QObject* parent): QObject(parent) {} /// Parse this event with a known number of arguments. /// /// Argument count is required as some events can contain commas /// in the last argument, which can be ignored as long as the count is known. Q_INVOKABLE [[nodiscard]] QVector parse(qint32 argumentCount) const; [[nodiscard]] QVector parseView(qint32 argumentCount) const; [[nodiscard]] QString nameStr() const; [[nodiscard]] QString dataStr() const; void reset(); QByteArrayView name; QByteArrayView data; }; class HyprlandIpc: public QObject { Q_OBJECT; public: static HyprlandIpc* instance(); [[nodiscard]] QString requestSocketPath() const; [[nodiscard]] QString eventSocketPath() const; void makeRequest(const QByteArray& request, const std::function& callback); void dispatch(const QString& request); [[nodiscard]] HyprlandMonitor* monitorFor(QuickshellScreenInfo* screen); [[nodiscard]] HyprlandMonitor* focusedMonitor() const; void setFocusedMonitor(HyprlandMonitor* monitor); [[nodiscard]] ObjectModel* monitors(); [[nodiscard]] ObjectModel* workspaces(); // No byId because these preemptively create objects. The given id is set if created. HyprlandWorkspace* findWorkspaceByName(const QString& name, bool createIfMissing, qint32 id = -1); HyprlandMonitor* findMonitorByName(const QString& name, bool createIfMissing, qint32 id = -1); // canCreate avoids making ghost workspaces when the connection races void refreshWorkspaces(bool canCreate); void refreshMonitors(bool canCreate); // The last argument may contain commas, so the count is required. [[nodiscard]] static QVector parseEventArgs(QByteArrayView event, quint16 count); signals: void connected(); void rawEvent(HyprlandIpcEvent* event); void focusedMonitorChanged(); private slots: void eventSocketError(QLocalSocket::LocalSocketError error) const; void eventSocketStateChanged(QLocalSocket::LocalSocketState state); void eventSocketReady(); void onFocusedMonitorDestroyed(); private: explicit HyprlandIpc(); void onEvent(HyprlandIpcEvent* event); QLocalSocket eventSocket; QString mRequestSocketPath; QString mEventSocketPath; bool valid = false; bool requestingMonitors = false; bool requestingWorkspaces = false; bool monitorsRequested = false; ObjectModel mMonitors {this}; ObjectModel mWorkspaces {this}; HyprlandMonitor* mFocusedMonitor = nullptr; //HyprlandWorkspace* activeWorkspace = nullptr; HyprlandIpcEvent event {this}; }; } // namespace qs::hyprland::ipc