@@ -31,19 +31,19 @@ Q_LOGGING_CATEGORY(logI3IpcEvents, "quickshell.I3.ipc.events", QtWarningMsg);
31
31
namespace qs ::i3::ipc {
32
32
33
33
QVector<Event> I3Ipc::makeRequest (const QByteArray& request) {
34
+
34
35
this ->commandSocket .write (request);
35
36
this ->commandSocket .flush ();
36
37
37
38
if (this ->commandSocket .waitForReadyRead ()) {
38
- auto dataRaw = this ->commandSocket .readAll ();
39
- return I3Ipc::parseResponse (dataRaw);
39
+ return I3Ipc::parseResponse (this ->commandSocketDs );
40
40
} else {
41
41
qCWarning (logI3Ipc) << " Timeout while waiting for read for" << request;
42
42
return {};
43
43
}
44
44
}
45
45
46
- void I3Ipc::dispatch (const QString& payload) {
46
+ QJsonArray I3Ipc::dispatch (const QString& payload) {
47
47
auto message = I3Ipc::buildRequestMessage (EventCode::RUN_COMMAND, payload.toLocal8Bit ());
48
48
49
49
QVector<Event> res = this ->makeRequest (message);
@@ -63,6 +63,8 @@ void I3Ipc::dispatch(const QString& payload) {
63
63
<< jsonMessage[" error" ];
64
64
}
65
65
}
66
+
67
+ return data.array ();
66
68
}
67
69
68
70
QByteArray I3Ipc::buildRequestMessage (EventCode cmd, const QByteArray& payload) {
@@ -102,6 +104,7 @@ I3Ipc::I3Ipc() {
102
104
103
105
this ->liveEventSocket .write (message);
104
106
this ->liveEventSocket .flush ();
107
+ emit this ->connected ();
105
108
};
106
109
107
110
QObject::connect (
@@ -111,90 +114,70 @@ I3Ipc::I3Ipc() {
111
114
liveIPCconnectedCallback
112
115
);
113
116
117
+ this ->liveEventSocketDs .setDevice (&this ->liveEventSocket );
118
+ this ->commandSocketDs .setDevice (&this ->commandSocket );
119
+ this ->liveEventSocketDs .setByteOrder (static_cast <QDataStream::ByteOrder>(QSysInfo::ByteOrder));
120
+ this ->commandSocketDs .setByteOrder (static_cast <QDataStream::ByteOrder>(QSysInfo::ByteOrder));
121
+
114
122
this ->liveEventSocket .connectToServer (this ->mSocketPath );
115
123
this ->commandSocket .connectToServer (this ->mSocketPath );
116
-
117
124
this ->refreshWorkspaces ();
118
125
this ->refreshMonitors ();
119
126
}
120
127
121
128
void I3Ipc::eventSocketReady () {
122
- while (true ) {
123
- auto rawEvent = this ->liveEventSocket .readAll ();
124
- if (rawEvent.isEmpty ()) break ;
125
-
126
- for (auto & [type, data]: I3Ipc::parseResponse (rawEvent)) {
127
- this ->event .mCode = type;
128
- this ->event .mData = data;
129
+ for (auto & [type, data]: I3Ipc::parseResponse (this ->liveEventSocketDs )) {
130
+ this ->event .mCode = type;
131
+ this ->event .mData = data;
129
132
130
- this ->onEvent (&this ->event );
131
- emit this ->rawEvent (&this ->event );
132
- }
133
+ this ->onEvent (&this ->event );
134
+ emit this ->rawEvent (&this ->event );
133
135
}
134
136
}
135
137
136
- QVector<Event> I3Ipc::parseResponse (QByteArray rawEvent) {
138
+ QVector<Event> I3Ipc::parseResponse (QDataStream& rawEvent) {
137
139
QVector<std::tuple<EventCode, QJsonDocument>> events;
138
140
const int magicLen = 6 ;
139
- const int header = 8 + magicLen;
140
141
141
- while (!rawEvent.isEmpty ()) {
142
- auto magicSeqInd = rawEvent.indexOf (MAGIC );
142
+ while (!rawEvent.atEnd ()) {
143
+ rawEvent.startTransaction ( );
143
144
144
- if (magicSeqInd < 0 ) {
145
- qCWarning (logI3Ipc) << " No magic sequence found in string." ;
146
- break ;
147
- };
148
-
149
- if (magicSeqInd > 0 ) {
150
- rawEvent = rawEvent.sliced (magicSeqInd);
151
- }
145
+ QByteArray buffer (6 , 0 );
146
+ qint32 size = 0 ;
147
+ qint32 type = EventCode::UNKNOWN;
152
148
153
- auto eventLength = rawEvent.length ();
149
+ rawEvent.readRawData (buffer.data (), magicLen);
150
+ rawEvent >> size;
151
+ rawEvent >> type;
154
152
155
- if (eventLength < header) {
156
- qCWarning (logI3Ipc) << " Event isn't long enough to hold the header data (14 bytes)." ;
153
+ if (buffer != MAGIC.data ()) {
154
+ qCWarning (logI3Ipc) << " No magic sequence found in string." << buffer;
155
+ rawEvent.rollbackTransaction ();
157
156
break ;
158
157
};
159
158
160
- rawEvent = rawEvent.sliced (magicLen);
161
-
162
- QDataStream ds (rawEvent);
163
-
164
- ds.setByteOrder (static_cast <QDataStream::ByteOrder>(QSysInfo::ByteOrder));
165
-
166
- qint32 size = 0 ;
167
- qint32 type = EventCode::UNKNOWN;
168
-
169
- ds >> size;
170
- ds >> type;
171
-
172
159
if (I3IpcEvent::intToEvent (type) == EventCode::UNKNOWN) {
173
- qCWarning (logI3Ipc) << " Received unknown event" << rawEvent;
160
+ qCWarning (logI3Ipc) << " Received unknown event" ;
161
+ rawEvent.rollbackTransaction ();
174
162
break ;
175
163
}
176
164
177
- auto maxPayloadLength = eventLength - header ;
165
+ QByteArray payload (size, Qt::Uninitialized) ;
178
166
179
- if (maxPayloadLength < size) {
180
- qCWarning (logI3Ipc) << " Payload is smaller than length advertised in header, skipping... ("
181
- << maxPayloadLength << " vs" << size << " )" ;
182
- break ;
183
- }
184
-
185
- rawEvent = rawEvent.sliced (8 );
167
+ rawEvent.readRawData (payload.data (), size);
186
168
187
169
QJsonParseError e;
188
170
189
- auto data = QJsonDocument::fromJson (rawEvent. sliced ( 0 , size) , &e);
171
+ auto data = QJsonDocument::fromJson (payload , &e);
190
172
191
173
if (e.error != QJsonParseError::NoError) {
192
- qCWarning (logI3Ipc) << " Invalid JSON value:" << e.errorString () << " \n\t " << rawEvent;
174
+ qCWarning (logI3Ipc) << " Invalid JSON value:" << e.errorString ();
175
+ rawEvent.rollbackTransaction ();
176
+ break ;
193
177
} else {
178
+ if (!rawEvent.commitTransaction ()) break ;
194
179
events.push_back (std::tuple (I3IpcEvent::intToEvent (type), data));
195
180
}
196
-
197
- rawEvent = rawEvent.sliced (size);
198
181
}
199
182
200
183
return events;
@@ -234,6 +217,10 @@ void I3Ipc::setFocusedWorkspace(I3Workspace* workspace) {
234
217
this ->mFocusedWorkspace = workspace;
235
218
236
219
if (workspace != nullptr ) {
220
+ if (auto * monitor = this ->mFocusedWorkspace ->monitor ()) {
221
+ monitor->setFocusedWorkspace (this ->mFocusedWorkspace );
222
+ }
223
+
237
224
QObject::connect (workspace, &QObject::destroyed, this , &I3Ipc::onFocusedWorkspaceDestroyed);
238
225
workspace->setFocus (true );
239
226
this ->setFocusedMonitor (workspace->monitor ());
@@ -428,28 +415,37 @@ void I3Ipc::handleWorkspaceEvent(I3IpcEvent* event) {
428
415
429
416
auto workspaceData = event->mData [" current" ];
430
417
431
- auto * workspace = new I3Workspace (this );
418
+ auto * workspace = this ->findWorkspaceByID (workspaceData[" id" ].toInt (-1 ));
419
+
420
+ if (workspace == nullptr ) {
421
+ workspace = new I3Workspace (this );
422
+ }
432
423
433
424
if (workspaceData.isObject ()) {
434
425
workspace->updateFromObject (workspaceData.toObject ().toVariantMap ());
435
426
}
436
427
437
428
this ->mWorkspaces .insertObject (workspace);
438
429
qCInfo (logI3Ipc) << " Added workspace to list" ;
439
-
440
430
} else if (change == " focus" ) {
441
431
auto oldData = event->mData [" old" ];
442
432
auto newData = event->mData [" current" ];
443
433
auto oldName = oldData[" name" ].toString ();
444
434
auto newName = newData[" name" ].toString ();
445
435
446
436
qCInfo (logI3IpcEvents) << " Focus changed: " << oldName << " ->" << newName;
447
- auto * oldWorkspace = this ->findWorkspaceByName (oldName);
437
+
438
+ if (auto * oldWorkspace = this ->findWorkspaceByName (oldName)) {
439
+ oldWorkspace->updateFromObject (oldData.toObject ().toVariantMap ());
440
+ }
441
+
448
442
auto * newWorkspace = this ->findWorkspaceByName (newName);
449
443
450
- oldWorkspace->updateFromObject (oldData.toObject ().toVariantMap ());
451
- newWorkspace->updateFromObject (newData.toObject ().toVariantMap ());
444
+ if (newWorkspace == nullptr ) {
445
+ newWorkspace = new I3Workspace (this );
446
+ }
452
447
448
+ newWorkspace->updateFromObject (newData.toObject ().toVariantMap ());
453
449
this ->setFocusedWorkspace (newWorkspace);
454
450
} else if (change == " empty" ) {
455
451
auto name = event->mData [" current" ][" name" ].toString ();
@@ -493,6 +489,14 @@ I3Monitor* I3Ipc::monitorFor(QuickshellScreenInfo* screen) {
493
489
return this ->findMonitorByName (screen->name ());
494
490
}
495
491
492
+ I3Workspace* I3Ipc::findWorkspaceByID (qint32 id) {
493
+ auto list = this ->mWorkspaces .valueList ();
494
+ auto workspaceIter =
495
+ std::find_if (list.begin (), list.end (), [id](const I3Workspace* m) { return m->id () == id; });
496
+
497
+ return workspaceIter == list.end () ? nullptr : *workspaceIter;
498
+ }
499
+
496
500
I3Workspace* I3Ipc::findWorkspaceByName (const QString& name) {
497
501
auto list = this ->mWorkspaces .valueList ();
498
502
auto workspaceIter = std::find_if (list.begin (), list.end (), [name](const I3Workspace* m) {
0 commit comments