qi3pc 1.0.0
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 {
69 Workspace = I3_IPC_EVENT_WORKSPACE,
71 Output = I3_IPC_EVENT_OUTPUT,
73 Mode = I3_IPC_EVENT_MODE,
75 Window = I3_IPC_EVENT_WINDOW,
77 BarUpdate = I3_IPC_EVENT_BARCONFIG_UPDATE,
79 Binding = I3_IPC_EVENT_BINDING,
81 Shutdown = I3_IPC_EVENT_SHUTDOWN,
83 Tick = I3_IPC_EVENT_TICK
84 };
85
92 enum class IpcType : quint32
93 {
94 Command = I3_IPC_REPLY_TYPE_COMMAND,
95 Workspaces = I3_IPC_REPLY_TYPE_WORKSPACES,
96 Subscribe = I3_IPC_REPLY_TYPE_SUBSCRIBE,
97 Outputs = I3_IPC_REPLY_TYPE_OUTPUTS,
98 Tree = I3_IPC_REPLY_TYPE_TREE,
99 Marks = I3_IPC_REPLY_TYPE_MARKS,
100 BarConfig = I3_IPC_REPLY_TYPE_BAR_CONFIG,
101 Version = I3_IPC_REPLY_TYPE_VERSION,
102 BindingModes = I3_IPC_REPLY_TYPE_BINDING_MODES,
103 Config = I3_IPC_REPLY_TYPE_CONFIG,
104 Tick = I3_IPC_REPLY_TYPE_TICK,
105 Sync = I3_IPC_REPLY_TYPE_SYNC,
106 BindingState = I3_IPC_REPLY_TYPE_GET_BINDING_STATE
107 };
108
117 {
118 Empty,
119 Focus,
120 Init,
121 Move,
122 Reload,
123 Rename,
124 Restored,
125 Urgent,
126 Unknown
127 };
128
135 enum class OutputChange
136 {
137 Unspecified,
138 Unknown
139 };
140
147 enum class WindowChange
148 {
149 New,
150 Close,
151 Focus,
152 Title,
153 Fullscreen,
154 Move,
155 Floating,
156 Urgent,
157 Mark,
158 Unknown
159 };
160
167 enum class ShutdownChange
168 {
169 Restart,
170 Exit,
171 Unknown
172 };
173
180 enum class BindingChange
181 {
182 Run,
183 Unknown
184 };
185
187 using DataObject = std::optional<std::pair<QJsonObject, qint64>>;
188
190 using DataArray = std::optional<std::pair<QJsonArray, qint64>>;
191
193 using DataString = std::optional<std::pair<QString, qint64>>;
194
201 struct ParseError {
203 QString error;
204
206 QString input;
207
217
225 QString toString() const;
226
232 bool operator==(const ParseError& other) const;
233
246 static std::optional<ParseError> FromJSON(const QJsonObject& json);
247
248 private:
250 using QStringMemberPtr = QString ParseError::*;
251
253 inline static constexpr auto _MEMBERS = std::to_array<std::pair<const char*, QStringMemberPtr>>
254 ({
255 {"error", &ParseError::error},
256 {"input", &ParseError::input},
257 {"errorposition", &ParseError::errorPosition}
258 });
259 };
260
262 using Error = std::optional<ParseError>;
263
270 using CommandResults = std::vector<std::pair<bool, Error>>;
271
278 using Message = std::optional<std::pair<QJsonDocument, quint32>>;
279
284 explicit qi3pc(QObject* parent = nullptr);
285
291 explicit qi3pc(const QString& socketPath, QObject* parent = nullptr);
292
299 virtual ~qi3pc();
300
314 bool connect(int msecs = 1500);
315
322 bool isConnected();
323
332 bool disconnect(int msecs = 1500);
333
340 void subscribe(const QStringList& events);
341
349 static QString FindSocketPath();
350
357 static QString FindSocketPathFromI3Binary();
358
363 QString socketPath() const;
364
374 template<IpcType Type>
375 void sendMessage(const QByteArray& payload = QByteArray()) {
376 if constexpr(Type == IpcType::Subscribe || Type == IpcType::Tick) {
377 WritePayload(m_eventSocket, payload, Type);
378 if constexpr(Type == IpcType::Subscribe) {
379 m_eventSocket.flush();
380 }
381 } else {
382 WritePayload(m_messageSocket, payload, Type);
383 }
384 }
385
392 const DataArray& workspaces() const;
393
400 const DataObject& tree() const;
401
408 const DataArray& outputs() const;
409
416 const DataArray& marks() const;
417
426 const DataObject& barConfigs() const;
427
435 const DataObject& version() const;
436
443 const DataArray& bindingModes() const;
444
451 const DataObject& config() const;
452
459 const DataString& bindingState() const;
460
461public slots:
468 void fetchWorkspaces();
469
476 void fetchTree();
477
485 void fetchOutputs();
486
493 void fetchMarks();
494
504 void fetchBarConfig(const QString& id);
505
512 void fetchBarConfigs();
513
521 void fetchVersion();
522
530 void fetchBindingModes();
531
538 void fetchConfig();
539
546 void fetchBindingState();
547
548private:
554 Message processMessage(QLocalSocket& socket);
555
559 void processEvent();
560
564 void processReply();
565
570 void processWorkspaceEvent(const QJsonDocument& doc);
571
576 void processOutputEvent(const QJsonDocument& doc);
577
582 void processModeEvent(const QJsonDocument& doc);
583
588 void processWindowEvent(const QJsonDocument& doc);
589
594 void processBarUpdateEvent(const QJsonDocument& doc);
595
600 void processBindingEvent(const QJsonDocument& doc);
601
606 void processShutdownEvent(const QJsonDocument& doc);
607
612 void processTickEvent(const QJsonDocument& doc);
613
618 void processCommandReply(const QJsonDocument& doc);
619
624 void processWorkspaceReply(const QJsonDocument& doc);
625
630 void processOutputReply(const QJsonDocument& doc);
631
636 void processTreeReply(const QJsonDocument& doc);
637
642 void processMarkReply(const QJsonDocument& doc);
643
648 void processBarConfigReply(const QJsonDocument& doc);
649
654 void processVersionReply(const QJsonDocument& doc);
655
660 void processBindingModesReply(const QJsonDocument& doc);
661
666 void processConfigReply(const QJsonDocument& doc);
667
672 void processTickReply(const QJsonDocument& doc);
673
678 void processSyncReply(const QJsonDocument& doc);
679
684 void processBindingStateReply(const QJsonDocument& doc);
685
691 static WorkspaceChange WorkspaceChangeFromString(const QString& s);
692
698 static WindowChange WindowChangeFromString(const QString& s);
699
705 static ShutdownChange ShutdownChangeFromString(const QString& s);
706
712 static OutputChange OutputChangeFromString(const QString& s);
713
719 static BindingChange BindingChangeFromString(const QString& s);
720
728 static void WritePayload(QLocalSocket& socket, const QByteArray& payload, IpcType type);
729
730private:
731 QString m_socketPath;
732
733 QLocalSocket m_eventSocket;
734 QLocalSocket m_messageSocket;
735
745
746signals:
755
763 void tickSent(bool success);
764
772 void synced(bool success);
773
780 void subscribed(bool success);
781
789 const QJsonObject& current,
790 const QJsonObject& old);
796
803 void modeEvent(QString change, bool pango);
804
810 void windowEvent(qi3pc::WindowChange change, const QJsonObject& container);
811
816 void barUpdateEvent(const QJsonObject& doc);
817
826 void bindingEvent(qi3pc::BindingChange change, const QJsonObject& binding, const QString& mode);
827
833
838 void tickEvent(const QString& payload);
839
847
855
862
870
878 void barConfigUpdated(const QJsonObject& config);
879
887 void newBarConfig(const QString& id);
888
897
906
914
922};
923
924#endif // QI3PC_H
ShutdownChange
Types of change a shutdown event can have.
Definition qi3pc.h:168
void configUpdated(const qi3pc::DataObject &config)
The (cached) config have been updated.
DataArray m_workspaces
Definition qi3pc.h:737
void treeUpdated(const qi3pc::DataObject &tree)
The layout tree cache have been updated.
WindowChange
Types of change a window event can have.
Definition qi3pc.h:148
void barConfigUpdated(const QJsonObject &config)
A specific bar's (cached) config have been updated. At this point the configuration for the bar has b...
DataObject m_version
Definition qi3pc.h:741
std::vector< std::pair< bool, Error > > CommandResults
Pairs of qi3pc::Error and boolean.
Definition qi3pc.h:270
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:278
void barUpdateEvent(const QJsonObject &doc)
A bar's configuration have been updated.
QLocalSocket m_messageSocket
Definition qi3pc.h:734
void workspacesUpdated(const qi3pc::DataArray &workspaces)
The (cached) list of workspaces have been updated.
void synced(bool success)
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:262
void tickSent(bool success)
A tick message have been replied to by i3.
QString socketPath() const
Get the socket path selected at construction.
Definition qi3pc.cpp:533
bool connect(int msecs=1500)
Start listening to messages and events from the window manager.
Definition qi3pc.cpp:602
DataObject m_config
Definition qi3pc.h:744
const DataArray & marks() const
Get the (cached) list of set marks.
Definition qi3pc.cpp:561
void subscribed(bool success)
A subscribe message have been replied to.
DataString m_bindingState
Definition qi3pc.h:743
void bindingStateUpdated(const qi3pc::DataString &state)
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:739
void versionUpdated(const qi3pc::DataObject &version)
The (cached) i3 version have been updated.
void outputsUpdated(const qi3pc::DataArray &outputs)
The (cached) outputs have been updated.
void modeEvent(QString change, bool pango)
The binding mode changes.
static constexpr auto IpcMagicLength
Definition qi3pc.h:58
void windowEvent(qi3pc::WindowChange change, const QJsonObject &container)
A window changed.
QLocalSocket m_eventSocket
Definition qi3pc.h:733
void subscribe(const QStringList &events)
Subscribe to a list of events.
Definition qi3pc.cpp:656
void sendMessage(const QByteArray &payload=QByteArray())
Send a message with the specified type and payload to i3.
Definition qi3pc.h:375
const DataArray & workspaces() const
Get the list of (cached) workspaces.
Definition qi3pc.cpp:540
void newBarConfig(const QString &id)
A new bar config have been added to the cache.
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:671
IpcType
Types of message/replies the API send/expect to/from i3wm.
Definition qi3pc.h:93
static constexpr auto IpcMagicString
Definition qi3pc.h:57
DataObject m_barConfigs
Definition qi3pc.h:740
void tickEvent(const QString &payload)
A tick event is received from i3.
BindingChange
Types of change a binding event can have.
Definition qi3pc.h:181
void marksUpdated(const qi3pc::DataArray &marks)
The (cached) list of marks have been updated.
OutputChange
Types of change an output event can have.
Definition qi3pc.h:136
std::optional< std::pair< QJsonObject, qint64 > > DataObject
Optional pair of a JSON object with its last update time.
Definition qi3pc.h:187
WorkspaceChange
Types of change a workspace event can have.
Definition qi3pc.h:117
DataArray m_bindingModes
Definition qi3pc.h:742
bool disconnect(int msecs=1500)
Stop listening to messages and events from the window manager.
Definition qi3pc.cpp:623
qi3pc(QObject *parent=nullptr)
Construct a qi3pc object.
Definition qi3pc.cpp:28
void bindingEvent(qi3pc::BindingChange change, const QJsonObject &binding, const QString &mode)
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:738
void commandRan(qi3pc::CommandResults result)
A command have been ran by i3.
void shutdownEvent(qi3pc::ShutdownChange change)
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)
The workspaces changed.
std::optional< std::pair< QString, qint64 > > DataString
Optional pair of a string with its last update time.
Definition qi3pc.h:193
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)
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:190
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:736
QString m_socketPath
Definition qi3pc.h:731
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:201
static constexpr auto _MEMBERS
Mapping of i3wm's parse error reply's attributes to members of ParseError.
Definition qi3pc.h:253
QString errorPosition
The position where the error was detected in the input.
Definition qi3pc.h:216
QString ParseError::* QStringMemberPtr
QString member pointer of ParseError.
Definition qi3pc.h:250
QString input
The command that failed to run.
Definition qi3pc.h:206
QString toString() const
Convert to a json like string.
Definition qi3pc.cpp:775
QString error
Human readble error message.
Definition qi3pc.h:203
bool operator==(const ParseError &other) const
Memberwise comparison of this ParseError and another.
Definition qi3pc.cpp:768
static std::optional< ParseError > FromJSON(const QJsonObject &json)
Build an optional ParseError from a QJsonObject.
Definition qi3pc.cpp:752