qi3pc 1.0.0.1
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)) {
69 case IpcEvent::Workspace:
71 break;
72 case IpcEvent::Output:
74 break;
75 case IpcEvent::Mode:
76 processModeEvent(data);
77 break;
78 case IpcEvent::Window:
80 break;
81 case IpcEvent::BarUpdate:
83 break;
84 case IpcEvent::Binding:
86 break;
87 case IpcEvent::Shutdown:
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)) {
100 case IpcType::Subscribe:
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;
130 case IpcType::Workspaces:
132 break;
133 case IpcType::Subscribe:
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;
146 case IpcType::BarConfig:
148 break;
149 case IpcType::Version:
151 break;
152 case IpcType::BindingModes:
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;
165 case IpcType::BindingState:
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();
611 }
612
613 if (m_eventSocket.state() != QLocalSocket::ConnectedState)
614 {
615 m_eventSocket.waitForConnected();
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();
631 }
632
633 if (m_eventSocket.state() != QLocalSocket::UnconnectedState)
634 {
635 m_eventSocket.waitForDisconnected();
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::sendTick(const QByteArray& payload)
657{
658 WritePayload(m_eventSocket, payload, IpcType::Tick);
659}
660
661void
662qi3pc::subscribe(const QStringList& events)
663{
664 if (events.isEmpty()) {
665 qCWarning(Qi3pcLogger) << "Requested to subscibe to empty event list. Nothing to do.";
666 return;
667 }
668
671 QJsonDocument(QJsonArray::fromStringList(events)).toJson(),
672 IpcType::Subscribe);
673 m_eventSocket.flush();
674}
675
676void
677qi3pc::WritePayload(QLocalSocket& socket, const QByteArray& payload, IpcType type)
678{
679 QByteArray message;
680 QDataStream stream(&message, QIODevice::WriteOnly);
681
682 stream.writeRawData(qi3pc::IpcMagicString.data(), qi3pc::IpcMagicLength);
683
684 qint32 size = payload.size();
685 stream.writeRawData(reinterpret_cast<const char*>(&size), sizeof size);
686 stream.writeRawData(reinterpret_cast<const char*>(&type), sizeof type);
687
688 if (size > 0) {
689 stream.writeRawData(payload.constData(), size);
690 }
691
692 socket.write(message);
693}
694
695void
700
701void
706
707void
712
713void
718
719void
724
725void
730
731void
736
737void
742
743void
744qi3pc::fetchBarConfig(const QString& id)
745{
746 QByteArray payload;
747 payload.append(id.toStdString().c_str());
749}
750
751void
756
758qi3pc::ParseError::FromJSON(const QJsonObject& json)
759{
760 if(!json.contains("parse_error")) {
761 return {};
762 }
763 auto ret = ParseError {};
764 for (const auto& [name, member]: ParseError::_MEMBERS) {
765 if (json.contains(name)) {
766 ret.*member = json[name].toString();
767 }
768 }
769
770 return ret;
771}
772
773bool
775 return error == other.error &&
776 input == other.input &&
778}
779
780QString
782{
783 auto str = QString("{");
784 for (const auto& [name, member]: ParseError::_MEMBERS) {
785 str += QString(name) + ":'" + this->*member + "',";
786 }
787
788 return str + "}";
789}
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 processOutputEvent(const QJsonDocument &doc)
Handle data received from an output event.
Definition qi3pc.cpp:305
void barConfigUpdated(const QJsonObject &config)
Signal emitted when a specific bar's (cached) config have been updated. At this point the configurati...
void fetchConfig()
Signal to emit to trigger an update of the (cached) config.
Definition qi3pc.cpp:732
void processBindingEvent(const QJsonDocument &doc)
Handle data received from a binding event.
Definition qi3pc.cpp:343
void sendMessage(const QByteArray &payload=QByteArray())
Send a message with the specified type and payload to i3.
Definition qi3pc.h:368
void fetchBarConfigs()
Signal to emit to update the list of bar configurations.
Definition qi3pc.cpp:738
DataObject m_version
Definition qi3pc.h:733
void fetchBindingModes()
Signal to emit to trigger an update of the (cached) list of modes.
Definition qi3pc.cpp:726
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.
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
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.
void processSyncReply(const QJsonDocument &doc)
Handle data received from a sync reply.
Definition qi3pc.cpp:277
DataString m_bindingState
Definition qi3pc.h:735
void fetchBarConfig(const QString &id)
Signal to emit to update the (cached) configuration of a certain bar.
Definition qi3pc.cpp:744
void processBarUpdateEvent(const QJsonDocument &doc)
Handle data received from a bar update event.
Definition qi3pc.cpp:337
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.
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:702
void processReply()
Read data from the message socket.
Definition qi3pc.cpp:116
DataArray m_marks
Definition qi3pc.h:731
void fetchOutputs()
Signal to emit to trigger an update of the (cached) outputs.
Definition qi3pc.cpp:708
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 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:752
void windowEvent(qi3pc::WindowChange change, const QJsonObject &container)
Signal emitted when a window changes.
static WorkspaceChange WorkspaceChangeFromString(const QString &s)
Convert a string into a workspace change object.
Definition qi3pc.cpp:377
QLocalSocket m_eventSocket
Definition qi3pc.h:725
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:662
void fetchMarks()
Signal to emit to trigger an update of the (cached) list of marks.
Definition qi3pc.cpp:714
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)
Signal emitted when 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:720
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
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:677
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
void sendTick(const QByteArray &payload=QByteArray())
Send a tick message with the spoecified payload.
Definition qi3pc.cpp:656
IpcType
Types of message/replies the API send/expect to/from i3wm.
Definition qi3pc.h:85
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: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 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)
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.
void processEvent()
Read data from the event socket.
Definition qi3pc.cpp:58
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
void processCommandReply(const QJsonDocument &doc)
Handle data received from a run command reply.
Definition qi3pc.cpp:176
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
void fetchWorkspaces()
Signal to emit to trigger an update of the list of workspace cache.
Definition qi3pc.cpp:696
void processOutputReply(const QJsonDocument &doc)
Handle data received from an output reply.
Definition qi3pc.cpp:210
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 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)
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 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: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 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