qi3pc 1.0.0.1
Qt bindings for i3wm's IPC interface
Loading...
Searching...
No Matches
qi3pc.h
1/* \author Hantz Vius
2 *
3 * \copyright Copyright (C) 2019-2025 Hantz Vius
4 *
5 * \license{
6 * This file is part of qi3pc.
7 *
8 * qi3pc is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU Affero General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Affero General Public License for more details.
17 *
18 * You should have received a copy of the GNU Affero General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>.}
20*/
21
22
23
24#ifndef QI3PC_H
25#define QI3PC_H
26
27#include "qi3pc_global.h"
28#include <QtNetwork/qlocalsocket.h>
29#include <QDebug>
30#include <QJsonArray>
31#include <QJsonDocument>
32#include <QJsonObject>
33#include <QMutexLocker>
34#include <QProcessEnvironment>
35#include <QTime>
36
37#include <i3/ipc.h>
38
39#include <optional>
40#include <string>
41#include <QLoggingCategory>
42
43Q_DECLARE_LOGGING_CATEGORY(Qi3pcLogger);
52class QI3PCSHARED_EXPORT qi3pc : public QObject
53{
54 Q_OBJECT
55
56public:
57 static constexpr auto IpcMagicString = std::string("i3-ipc");
58 static constexpr auto IpcMagicLength = IpcMagicString.length();
59
66 enum class IpcEvent : quint32
67 {
68 Workspace = I3_IPC_EVENT_WORKSPACE,
69 Output = I3_IPC_EVENT_OUTPUT,
70 Mode = I3_IPC_EVENT_MODE,
71 Window = I3_IPC_EVENT_WINDOW,
72 BarUpdate = I3_IPC_EVENT_BARCONFIG_UPDATE,
73 Binding = I3_IPC_EVENT_BINDING,
74 Shutdown = I3_IPC_EVENT_SHUTDOWN,
75 Tick = I3_IPC_EVENT_TICK
76 };
77
84 enum class IpcType : quint32
85 {
86 Command = I3_IPC_REPLY_TYPE_COMMAND,
87 Workspaces = I3_IPC_REPLY_TYPE_WORKSPACES,
88 Subscribe = I3_IPC_REPLY_TYPE_SUBSCRIBE,
89 Outputs = I3_IPC_REPLY_TYPE_OUTPUTS,
90 Tree = I3_IPC_REPLY_TYPE_TREE,
91 Marks = I3_IPC_REPLY_TYPE_MARKS,
92 BarConfig = I3_IPC_REPLY_TYPE_BAR_CONFIG,
93 Version = I3_IPC_REPLY_TYPE_VERSION,
94 BindingModes = I3_IPC_REPLY_TYPE_BINDING_MODES,
95 Config = I3_IPC_REPLY_TYPE_CONFIG,
96 Tick = I3_IPC_REPLY_TYPE_TICK,
97 Sync = I3_IPC_REPLY_TYPE_SYNC,
98 BindingState = I3_IPC_REPLY_TYPE_GET_BINDING_STATE
99 };
100
109 {
110 Empty,
111 Focus,
112 Init,
113 Move,
114 Reload,
115 Rename,
116 Restored,
117 Urgent,
118 Unknown
119 };
120
127 enum class OutputChange
128 {
129 Unspecified,
130 Unknown
131 };
132
139 enum class WindowChange
140 {
141 New,
142 Close,
143 Focus,
144 Title,
145 Fullscreen,
146 Move,
147 Floating,
148 Urgent,
149 Mark,
150 Unknown
151 };
152
159 enum class ShutdownChange
160 {
161 Restart,
162 Exit,
163 Unknown
164 };
165
172 enum class BindingChange
173 {
174 Run,
175 Unknown
176 };
177
179 using DataObject = std::optional<std::pair<QJsonObject, qint64>>;
180
182 using DataArray = std::optional<std::pair<QJsonArray, qint64>>;
183
185 using DataString = std::optional<std::pair<QString, qint64>>;
186
193 struct ParseError {
195 QString error;
196
198 QString input;
199
209
217 QString toString() const;
218
224 bool operator==(const ParseError& other) const;
225
238 static std::optional<ParseError> FromJSON(const QJsonObject& json);
239
240 private:
242 using QStringMemberPtr = QString ParseError::*;
243
245 inline static constexpr auto _MEMBERS = std::to_array<std::pair<const char*, QStringMemberPtr>>
246 ({
247 {"error", &ParseError::error},
248 {"input", &ParseError::input},
249 {"errorposition", &ParseError::errorPosition}
250 });
251 };
252
254 using Error = std::optional<ParseError>;
255
262 using CommandResults = std::vector<std::pair<bool, Error>>;
263
270 using Message = std::optional<std::pair<QJsonDocument, quint32>>;
271
276 explicit qi3pc(QObject* parent = nullptr);
277
283 explicit qi3pc(const QString& socketPath, QObject* parent);
284
291 virtual ~qi3pc();
292
304 bool connect();
305
312 bool isConnected();
313
320 bool disconnect();
321
328 void subscribe(const QStringList& events);
329
337 static QString FindSocketPath();
338
345 static QString FindSocketPathFromI3Binary();
346
351 QString socketPath() const;
352
366 template<IpcType Type>
367 requires(Type != IpcType::Subscribe && Type != IpcType::Tick)
368 void sendMessage(const QByteArray& payload = QByteArray()) {
369 WritePayload(m_messageSocket, payload, Type);
370 }
371
376 void sendTick(const QByteArray& payload = QByteArray());
377
384 const DataArray& workspaces() const;
385
392 const DataObject& tree() const;
393
400 const DataArray& outputs() const;
401
408 const DataArray& marks() const;
409
418 const DataObject& barConfigs() const;
419
427 const DataObject& version() const;
428
435 const DataArray& bindingModes() const;
436
443 const DataObject& config() const;
444
451 const DataString& bindingState() const;
452
453public slots:
460 void fetchWorkspaces();
461
468 void fetchTree();
469
477 void fetchOutputs();
478
485 void fetchMarks();
486
496 void fetchBarConfig(const QString& id);
497
504 void fetchBarConfigs();
505
513 void fetchVersion();
514
522 void fetchBindingModes();
523
530 void fetchConfig();
531
538 void fetchBindingState();
539
540private:
546 Message processMessage(QLocalSocket& socket);
547
551 void processEvent();
552
556 void processReply();
557
562 void processWorkspaceEvent(const QJsonDocument& doc);
563
568 void processOutputEvent(const QJsonDocument& doc);
569
574 void processModeEvent(const QJsonDocument& doc);
575
580 void processWindowEvent(const QJsonDocument& doc);
581
586 void processBarUpdateEvent(const QJsonDocument& doc);
587
592 void processBindingEvent(const QJsonDocument& doc);
593
598 void processShutdownEvent(const QJsonDocument& doc);
599
604 void processTickEvent(const QJsonDocument& doc);
605
610 void processCommandReply(const QJsonDocument& doc);
611
616 void processWorkspaceReply(const QJsonDocument& doc);
617
622 void processOutputReply(const QJsonDocument& doc);
623
628 void processTreeReply(const QJsonDocument& doc);
629
634 void processMarkReply(const QJsonDocument& doc);
635
640 void processBarConfigReply(const QJsonDocument& doc);
641
646 void processVersionReply(const QJsonDocument& doc);
647
652 void processBindingModesReply(const QJsonDocument& doc);
653
658 void processConfigReply(const QJsonDocument& doc);
659
664 void processTickReply(const QJsonDocument& doc);
665
670 void processSyncReply(const QJsonDocument& doc);
671
676 void processBindingStateReply(const QJsonDocument& doc);
677
683 static WorkspaceChange WorkspaceChangeFromString(const QString& s);
684
690 static WindowChange WindowChangeFromString(const QString& s);
691
697 static ShutdownChange ShutdownChangeFromString(const QString& s);
698
704 static OutputChange OutputChangeFromString(const QString& s);
705
711 static BindingChange BindingChangeFromString(const QString& s);
712
720 static void WritePayload(QLocalSocket& socket, const QByteArray& payload, IpcType type);
721
722private:
723 QString m_socketPath;
724
725 QLocalSocket m_eventSocket;
726 QLocalSocket m_messageSocket;
727
737
738signals:
747
755 void tickSent(bool success);
756
765 void synced(bool success);
766
774 void subscribed(bool success);
775
783 const QJsonObject& current,
784 const QJsonObject& old);
790
797 void modeEvent(QString change, bool pango);
798
804 void windowEvent(qi3pc::WindowChange change, const QJsonObject& container);
805
811 void barUpdateEvent(const QJsonObject& doc);
812
822 void bindingEvent(qi3pc::BindingChange change, const QJsonObject& binding, const QString& mode);
823
829
837 void tickEvent(const QString& payload);
838
847
856
863
872
880 void barConfigUpdated(const QJsonObject& config);
881
890 void newBarConfig(const QString& id);
891
901
911
919
927};
928
929#endif // QI3PC_H
ShutdownChange
Types of change a shutdown event can have.
Definition qi3pc.h:160
void configUpdated(const qi3pc::DataObject &config)
Signal emitted when the (cached) config have been updated.
DataArray m_workspaces
Definition qi3pc.h:729
void treeUpdated(const qi3pc::DataObject &tree)
Signal emitted when the layout tree cache have been updated.
WindowChange
Types of change a window event can have.
Definition qi3pc.h:140
void barConfigUpdated(const QJsonObject &config)
Signal emitted when a specific bar's (cached) config have been updated. At this point the configurati...
void sendMessage(const QByteArray &payload=QByteArray())
Send a message with the specified type and payload to i3.
Definition qi3pc.h:368
DataObject m_version
Definition qi3pc.h:733
std::vector< std::pair< bool, Error > > CommandResults
Pairs of qi3pc::Error and boolean.
Definition qi3pc.h:262
std::optional< std::pair< QJsonDocument, quint32 > > Message
Optional pair of a JSON document with a qi3pc::IpcType received with a message or an event before it ...
Definition qi3pc.h:270
void barUpdateEvent(const QJsonObject &doc)
Signal emitted when a bar's configuration have been updated.
QLocalSocket m_messageSocket
Definition qi3pc.h:726
void workspacesUpdated(const qi3pc::DataArray &workspaces)
Signal emitted when the (cached) list of workspaces have been updated.
void synced(bool success)
Signal emitted when a sync message have been replied to by i3.
std::optional< ParseError > Error
Optional qi3pc::ParseError. The optional is empty when the error could not be parsed.
Definition qi3pc.h:254
void tickSent(bool success)
Signal emitted when a tick have been processed by i3.
QString socketPath() const
Get the socket path selected at construction.
Definition qi3pc.cpp:533
DataObject m_config
Definition qi3pc.h:736
const DataArray & marks() const
Get the (cached) list of set marks.
Definition qi3pc.cpp:561
void subscribed(bool success)
Signal emitted when a subscribe message have been replied to.
DataString m_bindingState
Definition qi3pc.h:735
void bindingStateUpdated(const qi3pc::DataString &state)
Signal emitted when the (cached) current binding state have been updated.
void outputEvent(qi3pc::OutputChange change)
Signal emitted when the output(s) change.
DataArray m_marks
Definition qi3pc.h:731
void versionUpdated(const qi3pc::DataObject &version)
Signal emitted when the (cached) i3 version have been updated.
void outputsUpdated(const qi3pc::DataArray &outputs)
Signal emitted when (cached) outputs have been updated.
bool connect()
Start listening to messages and events from the window manager.
Definition qi3pc.cpp:602
void modeEvent(QString change, bool pango)
Signal emitted when the binding mode changes.
static constexpr auto IpcMagicLength
Definition qi3pc.h:58
void windowEvent(qi3pc::WindowChange change, const QJsonObject &container)
Signal emitted when a window changes.
QLocalSocket m_eventSocket
Definition qi3pc.h:725
void subscribe(const QStringList &events)
Subscribe to a list of events.
Definition qi3pc.cpp:662
const DataArray & workspaces() const
Get the list of (cached) workspaces.
Definition qi3pc.cpp:540
void newBarConfig(const QString &id)
Signal emitted when a new bar config have been added to the cache.
bool disconnect()
Stop listening to messages and events from the window manager.
Definition qi3pc.cpp:623
static QString FindSocketPath()
Find the path to the i3 ipc local unix socket.
Definition qi3pc.cpp:509
static void WritePayload(QLocalSocket &socket, const QByteArray &payload, IpcType type)
Send a message with the specified type and payload to i3 using the specified socket.
Definition qi3pc.cpp:677
IpcType
Types of message/replies the API send/expect to/from i3wm.
Definition qi3pc.h:85
static constexpr auto IpcMagicString
Definition qi3pc.h:57
DataObject m_barConfigs
Definition qi3pc.h:732
void tickEvent(const QString &payload)
Signal emitted when subscribing to tick events or when a tick message have been sent to the ipc conne...
BindingChange
Types of change a binding event can have.
Definition qi3pc.h:173
void marksUpdated(const qi3pc::DataArray &marks)
Signal emitted when the (cached) list of marks have been updated.
void commandRan(CommandResults result)
Signal emitted when a command have been ran by i3.
OutputChange
Types of change an output event can have.
Definition qi3pc.h:128
std::optional< std::pair< QJsonObject, qint64 > > DataObject
Optional pair of a JSON object with its last update time.
Definition qi3pc.h:179
WorkspaceChange
Types of change a workspace event can have.
Definition qi3pc.h:109
DataArray m_bindingModes
Definition qi3pc.h:734
qi3pc(QObject *parent=nullptr)
Construct a qi3pc object.
Definition qi3pc.cpp:28
void bindingEvent(qi3pc::BindingChange change, const QJsonObject &binding, const QString &mode)
Signal emitteed when a binding have been triggered to run a command.
const DataObject & tree() const
Get the (cached) i3 layout tree.
Definition qi3pc.cpp:547
DataArray m_outputs
Definition qi3pc.h:730
void shutdownEvent(qi3pc::ShutdownChange change)
Signal emitted when the ipc socket is about to shutdown.
const DataObject & config() const
Get the (cached) data read from the config file.
Definition qi3pc.cpp:589
void workspaceEvent(qi3pc::WorkspaceChange change, const QJsonObject &current, const QJsonObject &old)
Signal emitted with a workspace event's data preprocessed.
std::optional< std::pair< QString, qint64 > > DataString
Optional pair of a string with its last update time.
Definition qi3pc.h:185
static QString FindSocketPathFromI3Binary()
Find the path to the i3 ipc local unix socket using the i3 binary.
Definition qi3pc.cpp:521
void bindingModesUpdated(const qi3pc::DataArray &modes)
Signal emitted when the (cached) list of modes have been updated.
std::optional< std::pair< QJsonArray, qint64 > > DataArray
Optional pair of a JSON array with its last update time.
Definition qi3pc.h:182
const DataObject & version() const
Get the (cached) i3 version object.
Definition qi3pc.cpp:575
bool isConnected()
Check if the connection to the ipc socket is established.
Definition qi3pc.cpp:643
DataObject m_tree
Definition qi3pc.h:728
QString m_socketPath
Definition qi3pc.h:723
const DataArray & outputs() const
Get the (cached) list of outputs.
Definition qi3pc.cpp:554
IpcEvent
Types of events offered by i3wm's IPC API.
Definition qi3pc.h:67
Container for the attributes of a parsing error from i3wm when trying to run an unparsable command;.
Definition qi3pc.h:193
static constexpr auto _MEMBERS
Mapping of i3wm's parse error reply's attributes to members of ParseError.
Definition qi3pc.h:245
QString errorPosition
The position where the error was detected in the input.
Definition qi3pc.h:208
QString ParseError::* QStringMemberPtr
QString member pointer of ParseError.
Definition qi3pc.h:242
QString input
The command that failed to run.
Definition qi3pc.h:198
QString toString() const
Convert to a json like string.
Definition qi3pc.cpp:781
QString error
Human readble error message.
Definition qi3pc.h:195
bool operator==(const ParseError &other) const
Memberwise comparison of this ParseError and another.
Definition qi3pc.cpp:774
static std::optional< ParseError > FromJSON(const QJsonObject &json)
Build an optional ParseError from a QJsonObject.
Definition qi3pc.cpp:758