qi3pc 1.0.0
Qt bindings for i3wm's IPC interface
Loading...
Searching...
No Matches
qi3pc.cpp
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#include <QDebug>
23
24#include "qi3pc.h"
25
26Q_LOGGING_CATEGORY(Qi3pcLogger, "qi3pc", QtMsgType::QtDebugMsg)
27
28qi3pc::qi3pc(QObject* parent)
29 : qi3pc(FindSocketPath(), parent)
30{}
31
32qi3pc::qi3pc(const QString& serverPath, QObject* parent)
33 : QObject(parent)
34{
35 m_socketPath = serverPath;
36
37 m_barConfigs = std::make_pair(QJsonObject(), QDateTime::currentMSecsSinceEpoch());
38 if (m_socketPath.isEmpty()) {
39 throw std::invalid_argument("The provided server path must not be empty.");
40 }
41
42 QObject::connect(
43 &m_eventSocket, &QLocalSocket::readyRead, this, &qi3pc::processEvent);
44 QObject::connect(
45 &m_messageSocket, &QLocalSocket::readyRead, this, &qi3pc::processReply);
46}
47
49{
50 m_eventSocket.close();
51 m_messageSocket.close();
52
53 m_eventSocket.abort();
54 m_messageSocket.abort();
55}
56
57void
59{
61 if (!m) {
62 return;
63 }
64
65 auto [data, type] = m.value();
66
67 if (type & (1u << 31)) {
68 switch (static_cast<IpcEvent>(type)) {
71 break;
74 break;
75 case IpcEvent::Mode:
76 processModeEvent(data);
77 break;
80 break;
83 break;
86 break;
89 break;
90 case IpcEvent::Tick:
91 processTickEvent(data);
92 break;
93 default:
94 std::string log = "Received event of unsupported type IpcType::%u";
95 qCWarning(Qi3pcLogger, log.c_str(), type, IpcType::Subscribe);
96 break;
97 }
98 } else {
99 switch (static_cast<IpcType>(type)) {
101 emit subscribed(data["success"].toBool());
102 break;
103 case IpcType::Tick:
104 processTickReply(data);
105 break;
106 default:
107 std::string log = "Received message IpcType::%u while expecting IpcEvent, IpcType::Subscribe (IpcType::%u),"
108 "or IpcType::Tick (IpcType::%u)";
109 qCWarning(Qi3pcLogger, log.c_str(), type, IpcType::Subscribe, IpcType::Tick);
110 break;
111 }
112 }
113}
114
115void
117{
119 if (!m) {
120 return;
121 }
122
123 auto [data, type] = m.value();
124
125 std::string log;
126 switch (static_cast<IpcType>(type)) {
127 case IpcType::Command:
129 break;
132 break;
134 log = "Received reply of type IpcType::Subscribe (IpcType::%u): unexpected.";
135 qCWarning(Qi3pcLogger, log.c_str(), IpcType::Subscribe);
136 break;
137 case IpcType::Outputs:
138 processOutputReply(data);
139 break;
140 case IpcType::Tree:
141 processTreeReply(data);
142 break;
143 case IpcType::Marks:
144 processMarkReply(data);
145 break;
148 break;
149 case IpcType::Version:
151 break;
154 break;
155 case IpcType::Config:
156 processConfigReply(data);
157 break;
158 case IpcType::Tick:
159 log = "Received reply of type IpcType::Tick (IpcType::%u): unexpected.";
160 qCWarning(Qi3pcLogger, log.c_str(), IpcType::Tick);
161 break;
162 case IpcType::Sync:
163 processSyncReply(data);
164 break;
167 break;
168 default:
169 log = "Received reply of unsupported type IpcType::%u.";
170 qCWarning(Qi3pcLogger, log.c_str(), type);
171 break;
172 }
173}
174
175void
176qi3pc::processCommandReply(const QJsonDocument& doc)
177{
178 auto results = doc.array();
179 if (results.empty()) {
180 qCWarning(Qi3pcLogger) << "Received empty command reply:" << doc.toJson();
181 emit commandRan({{false, ParseError{}}});
182 }
183
184 CommandResults result;
185 for (auto jsonObject: std::as_const(results)) {
186 auto object = jsonObject.toObject();
187 if (!object.contains("success")) {
188 qCWarning(Qi3pcLogger) << "Command reply does not contain success key. Skipping:" << object;
189 continue;
190 }
191
192 if (auto success = object["success"].toBool(); success) {
193 result.push_back({true, {}});
194 } else {
195 result.push_back({false, ParseError::FromJSON(object)});
196 }
197 }
198
199 emit commandRan(result);
200}
201
202void
203qi3pc::processWorkspaceReply(const QJsonDocument& doc)
204{
205 m_workspaces = std::make_pair(doc.array(), QDateTime::currentMSecsSinceEpoch());
207}
208
209void
210qi3pc::processOutputReply(const QJsonDocument& doc)
211{
212 m_outputs = std::make_pair(doc.array(), QDateTime::currentMSecsSinceEpoch());
214}
215
216void
217qi3pc::processTreeReply(const QJsonDocument& doc)
218{
219 m_tree = std::make_pair(doc.object(), QDateTime::currentMSecsSinceEpoch());
220 emit treeUpdated(m_tree);
221}
222
223void
224qi3pc::processMarkReply(const QJsonDocument& doc)
225{
226 m_marks = std::make_pair(doc.array(), QDateTime::currentMSecsSinceEpoch());
227 emit marksUpdated(m_marks);
228}
229
230void
231qi3pc::processBarConfigReply(const QJsonDocument& doc)
232{
233 if (const auto& ids = doc.array(); !ids.isEmpty()) {
234 for (auto ref : ids) {
235 if (auto id = ref.toString();
236 m_barConfigs->first[id] == QJsonValue::Null) {
237 emit newBarConfig(id);
238 }
239 }
240 } else {
241 auto id = doc["id"].toString();
242 auto config = doc.object();
243 m_barConfigs->first[id] = config;
244 m_barConfigs->second = QDateTime::currentMSecsSinceEpoch();
246 }
247}
248
249void
250qi3pc::processVersionReply(const QJsonDocument& doc)
251{
252 m_version = std::make_pair(doc.object(), QDateTime::currentMSecsSinceEpoch());
254}
255
256void
257qi3pc::processBindingModesReply(const QJsonDocument& doc)
258{
259 m_bindingModes = std::make_pair(doc.array(), QDateTime::currentMSecsSinceEpoch());
261}
262
263void
264qi3pc::processConfigReply(const QJsonDocument& doc)
265{
266 m_config = std::make_pair(doc.object(), QDateTime::currentMSecsSinceEpoch());
268}
269
270void
271qi3pc::processTickReply(const QJsonDocument& doc)
272{
273 emit tickSent(doc["success"].toBool());
274}
275
276void
277qi3pc::processSyncReply(const QJsonDocument& doc)
278{
279 emit synced(doc["success"].toBool());
280}
281
282void
283qi3pc::processBindingStateReply(const QJsonDocument& doc)
284{
285 m_bindingState = std::make_pair(doc["name"].toString(), QDateTime::currentMSecsSinceEpoch());
287}
288
289void
290qi3pc::processWorkspaceEvent(const QJsonDocument& doc)
291{
292 auto change = WorkspaceChangeFromString(doc["change"].toString());
293
294 if (change == WorkspaceChange::Unknown) {
295 qCWarning(Qi3pcLogger) << "Received workspace event with unknown change string" << doc["change"].toString();
296 return;
297 }
298
299 auto old = doc["old"].toObject();
300 auto current = doc["current"].toObject();
301 emit workspaceEvent(change, current, old);
302}
303
304void
305qi3pc::processOutputEvent(const QJsonDocument& data)
306{
307 auto change = OutputChangeFromString(data["change"].toString());
308
309 if (change == OutputChange::Unknown) {
310 qCWarning(Qi3pcLogger) << "Received output event with unknown change string" << data["change"].toString();
311 return;
312 }
313
314 emit outputEvent(change);
315}
316
317void
318qi3pc::processModeEvent(const QJsonDocument& doc)
319{
320 emit modeEvent(doc["change"].toString(), doc["pango_markup"].toBool());
321}
322
323void
324qi3pc::processWindowEvent(const QJsonDocument& doc)
325{
326 auto change = WindowChangeFromString(doc["change"].toString());
327
328 if (change == WindowChange::Unknown) {
329 qCWarning(Qi3pcLogger) << "Received window event with unknown change string" << doc["change"].toString();
330 return;
331 }
332
333 emit windowEvent(change, doc["container"].toObject());
334}
335
336void
337qi3pc::processBarUpdateEvent(const QJsonDocument& doc)
338{
339 emit barUpdateEvent(doc.object());
340}
341
342void
343qi3pc::processBindingEvent(const QJsonDocument& doc)
344{
345 auto change = BindingChangeFromString(doc["change"].toString());
346
347 if (change == BindingChange::Unknown) {
348 qCWarning(Qi3pcLogger) << "Received binding event with unknown change string" << doc["change"].toString();
349 return;
350 }
351
352 emit bindingEvent(change, doc["binding"].toObject(), doc["mode"].toString());
353}
354
355void
356qi3pc::processShutdownEvent(const QJsonDocument& doc)
357{
358 auto change = ShutdownChangeFromString(doc["change"].toString());
359
360 if (change == ShutdownChange::Unknown) {
361 qCWarning(Qi3pcLogger) << "Received shutdown event with unknown change string" << doc["change"].toString();
362 return;
363 }
364
365 emit shutdownEvent(change);
366}
367
368void
369qi3pc::processTickEvent(const QJsonDocument& doc)
370{
371 if(auto first = doc["first"].toBool(); !first) {
372 emit tickEvent(doc["payload"].toString());
373 }
374}
375
378{
379 if (s == "focus") {
381 } else if (s == "init") {
383 } else if (s == "empty") {
385 } else if (s == "urgent") {
387 } else if (s == "reload") {
389 } else if (s == "rename") {
391 } else if (s == "restored") {
393 } else if (s == "move") {
395 } else {
397 }
398}
399
402{
403 if (s == "new") {
404 return WindowChange::New;
405 } else if (s == "close") {
406 return WindowChange::Close;
407 } else if (s == "focus") {
408 return WindowChange::Focus;
409 } else if (s == "title") {
410 return WindowChange::Title;
411 } else if (s == "fullscreen_mode") {
413 } else if (s == "move") {
414 return WindowChange::Move;
415 } else if (s == "floating") {
417 } else if (s == "urgent") {
419 } else if (s == "mark") {
420 return WindowChange::Mark;
421 } else {
423 }
424}
425
428{
429 if (s == "restart") {
431 } else if (s == "exit") {
433 } else {
435 }
436}
437
440{
441 if (s == "unspecified") {
443 } else {
445 }
446}
447
450{
451 if (s == "run") {
452 return BindingChange::Run;
453 } else {
455 }
456}
457
459qi3pc::processMessage(QLocalSocket& socket)
460{
461 char c[IpcMagicLength];
462 if (auto read_size = socket.read(c, IpcMagicLength);
463 read_size != IpcMagicLength) {
464 qCWarning(Qi3pcLogger) << "Insufficient data read for IPC magic string. Seeked"
465 << IpcMagicLength <<"bytes. - Read" << read_size << "bytes.";
466 return {};
467 }
468
469 if (auto s = std::string(c, IpcMagicLength); s != IpcMagicString) {
470 qCWarning(Qi3pcLogger) << "Unexpected magic string in message. Expected"
471 << qi3pc::IpcMagicString << ". - Found" << s << ".";
472 return {};
473 }
474
475 quint32 size;
476 if (auto read_size = socket.read(reinterpret_cast<char*>(&size), sizeof size);
477 read_size != sizeof size) {
478 qCWarning(Qi3pcLogger) << "Insufficient data read for message size. Seeked"
479 << sizeof size <<"bytes. - Read" << read_size << "bytes.";
480 return {};
481 }
482
483 quint32 type;
484 if (auto read_size = socket.read(reinterpret_cast<char*>(&type), sizeof type);
485 read_size != sizeof type) {
486 qCWarning(Qi3pcLogger) << "Insufficient data read for message type. Seeked"
487 << sizeof type <<"bytes. - Read" << read_size << "bytes.";
488 return {};
489 }
490
491 QJsonParseError parseError;
492 auto payload = socket.read(size);
493
494 if (socket.bytesAvailable() > 0) {
495 emit socket.readyRead();
496 }
497
498 QJsonDocument data = QJsonDocument::fromJson(payload, &parseError);
499 if (parseError.error != QJsonParseError::NoError) {
500 qCWarning(Qi3pcLogger) << "Parsing message body failed - JSON parse error:"
501 << parseError.errorString() << "in:" << payload;
502 return {};
503 }
504
505 return std::make_pair(data, type);
506}
507
508QString
510{
511 if (auto path = QProcessEnvironment::systemEnvironment().value("I3SOCK");
512 !path.isEmpty()) {
513 return path;
514 }
515
516 // TODO: try to get socket path from root window property
518}
519
520QString
522{
523 QProcess process;
524 process.start("i3", QStringList("--get-socketpath"));
525 process.waitForReadyRead();
526 auto path = QString(process.readAllStandardOutput()).trimmed();
527 process.kill();
528 process.waitForFinished();
529 return path;
530}
531
532QString
534{
535 return m_socketPath;
536}
537
538const
541{
542 return m_workspaces;
543}
544
545const
548{
549 return m_tree;
550}
551
552const
555{
556 return m_outputs;
557}
558
559const
562{
563 return m_marks;
564}
565
566const
569{
570 return m_barConfigs;
571}
572
573const
576{
577 return m_version;
578}
579
580const
583{
584 return m_bindingModes;
585}
586
587const
590{
591 return m_config;
592}
593
594const
597{
598 return m_bindingState;
599}
600
601bool
603{
604
605 m_messageSocket.connectToServer(m_socketPath);
606 m_eventSocket.connectToServer(m_socketPath);
607
608 if (m_messageSocket.state() != QLocalSocket::ConnectedState)
609 {
610 m_messageSocket.waitForConnected(msecs);
611 }
612
613 if (m_eventSocket.state() != QLocalSocket::ConnectedState)
614 {
615 m_eventSocket.waitForConnected(msecs);
616 }
617
618 return m_messageSocket.state() == QLocalSocket::ConnectedState &&
619 m_eventSocket.state() == QLocalSocket::ConnectedState;
620}
621
622bool
624{
625 m_messageSocket.disconnectFromServer();
626 m_eventSocket.disconnectFromServer();
627
628 if (m_messageSocket.state() != QLocalSocket::UnconnectedState)
629 {
630 m_messageSocket.waitForDisconnected(msecs);
631 }
632
633 if (m_eventSocket.state() != QLocalSocket::UnconnectedState)
634 {
635 m_eventSocket.waitForDisconnected(msecs);
636 }
637
638 return m_messageSocket.state() == QLocalSocket::UnconnectedState &&
639 m_eventSocket.state() == QLocalSocket::UnconnectedState;
640}
641
642bool
644{
645 if (m_messageSocket.state() == QLocalSocket::ConnectingState ||
646 m_eventSocket.state() == QLocalSocket::ConnectingState) {
647 m_messageSocket.waitForConnected();
648 m_eventSocket.waitForConnected();
649 }
650
651 return m_messageSocket.state() == QLocalSocket::ConnectedState &&
652 m_eventSocket.state() == QLocalSocket::ConnectedState;
653}
654
655void
656qi3pc::subscribe(const QStringList& events)
657{
658 if (events.isEmpty()) {
659 qCWarning(Qi3pcLogger) << "Requested to subscibe to empty event list. Nothing to do.";
660 return;
661 }
662
665 QJsonDocument(QJsonArray::fromStringList(events)).toJson(),
667 m_eventSocket.flush();
668}
669
670void
671qi3pc::WritePayload(QLocalSocket& socket, const QByteArray& payload, IpcType type)
672{
673 QByteArray message;
674 QDataStream stream(&message, QIODevice::WriteOnly);
675
676 stream.writeRawData(qi3pc::IpcMagicString.data(), qi3pc::IpcMagicLength);
677
678 qint32 size = payload.size();
679 stream.writeRawData(reinterpret_cast<const char*>(&size), sizeof size);
680 stream.writeRawData(reinterpret_cast<const char*>(&type), sizeof type);
681
682 if (size > 0) {
683 stream.writeRawData(payload.constData(), size);
684 }
685
686 socket.write(message);
687}
688
689void
694
695void
700
701void
706
707void
712
713void
718
719void
724
725void
730
731void
736
737void
738qi3pc::fetchBarConfig(const QString& id)
739{
740 QByteArray payload;
741 payload.append(id.toStdString().c_str());
743}
744
745void
750
752qi3pc::ParseError::FromJSON(const QJsonObject& json)
753{
754 if(!json.contains("parse_error")) {
755 return {};
756 }
757 auto ret = ParseError {};
758 for (const auto& [name, member]: ParseError::_MEMBERS) {
759 if (json.contains(name)) {
760 ret.*member = json[name].toString();
761 }
762 }
763
764 return ret;
765}
766
767bool
769 return error == other.error &&
770 input == other.input &&
772}
773
774QString
776{
777 auto str = QString("{");
778 for (const auto& [name, member]: ParseError::_MEMBERS) {
779 str += QString(name) + ":'" + this->*member + "',";
780 }
781
782 return str + "}";
783}
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 processOutputEvent(const QJsonDocument &doc)
Handle data received from an output event.
Definition qi3pc.cpp:305
void barConfigUpdated(const QJsonObject &config)
A specific bar's (cached) config have been updated. At this point the configuration for the bar has b...
void fetchConfig()
Signal to emit to trigger an update of the (cached) config.
Definition qi3pc.cpp:726
void processBindingEvent(const QJsonDocument &doc)
Handle data received from a binding event.
Definition qi3pc.cpp:343
void fetchBarConfigs()
Signal to emit to update the list of bar configurations.
Definition qi3pc.cpp:732
DataObject m_version
Definition qi3pc.h:741
void fetchBindingModes()
Signal to emit to trigger an update of the (cached) list of modes.
Definition qi3pc.cpp:720
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.
void processBindingModesReply(const QJsonDocument &doc)
Handle data received in a binding mode reply.
Definition qi3pc.cpp:257
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.
void processSyncReply(const QJsonDocument &doc)
Handle data received from a sync reply.
Definition qi3pc.cpp:277
DataString m_bindingState
Definition qi3pc.h:743
void fetchBarConfig(const QString &id)
Signal to emit to update the (cached) configuration of a certain bar.
Definition qi3pc.cpp:738
void processBarUpdateEvent(const QJsonDocument &doc)
Handle data received from a bar update event.
Definition qi3pc.cpp:337
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.
void processBarConfigReply(const QJsonDocument &doc)
Handle data received from a bar config reply.
Definition qi3pc.cpp:231
void fetchTree()
Signal to emit to trigger an update of the (cached) layout tree.
Definition qi3pc.cpp:696
void processReply()
Read data from the message socket.
Definition qi3pc.cpp:116
DataArray m_marks
Definition qi3pc.h:739
void fetchOutputs()
Signal to emit to trigger an update of the (cached) outputs.
Definition qi3pc.cpp:702
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 ShutdownChange ShutdownChangeFromString(const QString &s)
Convert a string into a shutdown change object.
Definition qi3pc.cpp:427
void processMarkReply(const QJsonDocument &doc)
Handle data received from a mark reply.
Definition qi3pc.cpp:224
static constexpr auto IpcMagicLength
Definition qi3pc.h:58
void fetchBindingState()
Request update of the (cached) binding state.
Definition qi3pc.cpp:746
void windowEvent(qi3pc::WindowChange change, const QJsonObject &container)
A window changed.
static WorkspaceChange WorkspaceChangeFromString(const QString &s)
Convert a string into a workspace change object.
Definition qi3pc.cpp:377
QLocalSocket m_eventSocket
Definition qi3pc.h:733
static BindingChange BindingChangeFromString(const QString &s)
Convert a string into a binding change object.
Definition qi3pc.cpp:449
void processWindowEvent(const QJsonDocument &doc)
Handle data received from a window event.
Definition qi3pc.cpp:324
void subscribe(const QStringList &events)
Subscribe to a list of events.
Definition qi3pc.cpp:656
void fetchMarks()
Signal to emit to trigger an update of the (cached) list of marks.
Definition qi3pc.cpp:708
void sendMessage(const QByteArray &payload=QByteArray())
Send a message with the specified type and payload to i3.
Definition qi3pc.h:375
void processVersionReply(const QJsonDocument &doc)
Handle data received from a version reply.
Definition qi3pc.cpp:250
static WindowChange WindowChangeFromString(const QString &s)
Convert a string into a window change object.
Definition qi3pc.cpp:401
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.
void processWorkspaceReply(const QJsonDocument &doc)
Handle data received from a workspace reply.
Definition qi3pc.cpp:203
void fetchVersion()
Signal to emit to trigger a cache update for the i3wm version.
Definition qi3pc.cpp:714
static QString FindSocketPath()
Find the path to the i3 ipc local unix socket.
Definition qi3pc.cpp:509
void processConfigReply(const QJsonDocument &doc)
Handle data received from a config reply.
Definition qi3pc.cpp:264
const DataString & bindingState() const
Get the (cached) binding state.
Definition qi3pc.cpp:596
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
void processTickReply(const QJsonDocument &doc)
Handle data received from a tick reply.
Definition qi3pc.cpp:271
void processTickEvent(const QJsonDocument &doc)
Handle data received from a tick event.
Definition qi3pc.cpp:369
void processBindingStateReply(const QJsonDocument &doc)
Handle data received from a binding state event reply.
Definition qi3pc.cpp:283
IpcType
Types of message/replies the API send/expect to/from i3wm.
Definition qi3pc.h:93
const DataArray & bindingModes() const
Get the (cached) list of binding modes.
Definition qi3pc.cpp:582
static constexpr auto IpcMagicString
Definition qi3pc.h:57
void processTreeReply(const QJsonDocument &doc)
Handle data received from a tree reply.
Definition qi3pc.cpp:217
void processShutdownEvent(const QJsonDocument &doc)
Handle data received from a shutdowm event.
Definition qi3pc.cpp:356
virtual ~qi3pc()
Simple destructor for the qi3pc class.
Definition qi3pc.cpp:48
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 processModeEvent(const QJsonDocument &doc)
Handle data received from a mode event.
Definition qi3pc.cpp:318
Message processMessage(QLocalSocket &socket)
Read one message using the socket parameter.
Definition qi3pc.cpp:459
void marksUpdated(const qi3pc::DataArray &marks)
The (cached) list of marks have been updated.
void processEvent()
Read data from the event socket.
Definition qi3pc.cpp:58
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
void processCommandReply(const QJsonDocument &doc)
Handle data received from a run command reply.
Definition qi3pc.cpp:176
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
void fetchWorkspaces()
Signal to emit to trigger an update of the list of workspace cache.
Definition qi3pc.cpp:690
void processOutputReply(const QJsonDocument &doc)
Handle data received from an output reply.
Definition qi3pc.cpp:210
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 OutputChange OutputChangeFromString(const QString &s)
Convert a string into an output change object.
Definition qi3pc.cpp:439
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 DataObject & barConfigs() const
Get the (cached) list of all bar configurations.
Definition qi3pc.cpp:568
const DataArray & outputs() const
Get the (cached) list of outputs.
Definition qi3pc.cpp:554
void processWorkspaceEvent(const QJsonDocument &doc)
Handle data received from a workspace event.
Definition qi3pc.cpp:290
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 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