Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/x11/i3/ipc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ qt_add_library(quickshell-i3-ipc STATIC
monitor.cpp
controller.cpp
listener.cpp
scroller.cpp
window.cpp
)

qt_add_qml_module(quickshell-i3-ipc
Expand Down
40 changes: 34 additions & 6 deletions src/x11/i3/ipc/connection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ QString I3IpcEvent::type() const { return I3IpcEvent::eventToString(this->mCode)
QString I3IpcEvent::data() const { return QString::fromUtf8(this->mData.toJson()); }

EventCode I3IpcEvent::intToEvent(quint32 raw) {
if ((EventCode::Workspace <= raw && raw <= EventCode::Input)
|| (EventCode::RunCommand <= raw && raw <= EventCode::GetTree))
if ((EventCode::Workspace <= raw && raw <= EventCode::Trails)
|| (EventCode::RunCommand <= raw && raw <= EventCode::GetSpaces))
{
return static_cast<EventCode>(raw);
} else {
Expand All @@ -51,6 +51,14 @@ QString I3IpcEvent::eventToString(EventCode event) {
case EventCode::Subscribe: return "subscribe"; break;
case EventCode::GetOutputs: return "get_outputs"; break;
case EventCode::GetTree: return "get_tree"; break;
case EventCode::GetMarks: return "get_marks"; break;
case EventCode::GetVersion: return "get_version"; break;
case EventCode::GetBindingModes: return "get_binding_modes"; break;
case EventCode::GetBindingState: return "get_binding_state"; break;
case EventCode::GetInputs: return "get_inputs"; break;
case EventCode::GetScroller: return "get_scroller"; break;
case EventCode::GetTrails: return "get_trails"; break;
case EventCode::GetSpaces: return "get_spaces"; break;

case EventCode::Output: return "output"; break;
case EventCode::Workspace: return "workspace"; break;
Expand All @@ -62,23 +70,41 @@ QString I3IpcEvent::eventToString(EventCode event) {
case EventCode::Tick: return "tick"; break;
case EventCode::BarStateUpdate: return "bar_state_update"; break;
case EventCode::Input: return "input"; break;
case EventCode::Lua: return "lua"; break;
case EventCode::Scroller: return "scroller"; break;
case EventCode::Trails: return "trails"; break;

default: return "unknown"; break;
}
}

I3Ipc::I3Ipc(const QList<QString>& events): mEvents(events) {
auto sock = qEnvironmentVariable("I3SOCK");
auto sock = qEnvironmentVariable("SCROLLSOCK");

if (sock.isEmpty()) {
qCWarning(logI3Ipc) << "$I3SOCK is unset. Trying $SWAYSOCK.";
qCWarning(logI3Ipc) << "$SCROLLSOCK is unset. Trying $SWAYSOCK.";

sock = qEnvironmentVariable("SWAYSOCK");

if (sock.isEmpty()) {
qCWarning(logI3Ipc) << "$SWAYSOCK and I3SOCK are unset. Cannot connect to socket.";
return;
qCWarning(logI3Ipc) << "$SCROLLSOCK and $SWAYSOCK are unset. Trying $I3SOCK.";

sock = qEnvironmentVariable("I3SOCK");

if (sock.isEmpty()) {
qCWarning(logI3Ipc) << "$SCROLLSOCK, $SWAYSOCK and $I3SOCK are unset. Cannot connect to socket.";
return;
} else {
this->mCompositor = "i3";
}
} else {
this->mCompositor = "sway";
}
} else {
this->mCompositor = "scroll";
this->mEvents.append("scroller");
this->mEvents.append("trails");
this->mEvents.append("lua");
}

this->mSocketPath = sock;
Expand Down Expand Up @@ -215,4 +241,6 @@ void I3Ipc::eventSocketStateChanged(QLocalSocket::LocalSocketState state) {

QString I3Ipc::socketPath() const { return this->mSocketPath; }

QString I3Ipc::compositor() const { return this->mCompositor; }

} // namespace qs::i3::ipc
13 changes: 13 additions & 0 deletions src/x11/i3/ipc/connection.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,14 @@ enum EventCode {
Subscribe = 2,
GetOutputs = 3,
GetTree = 4,
GetMarks = 5,
GetVersion = 7,
GetBindingModes = 8,
GetBindingState = 12,
GetInputs = 100,
GetScroller = 120,
GetTrails = 121,
GetSpaces = 122,

Workspace = 0x80000000,
Output = 0x80000001,
Expand All @@ -30,6 +38,9 @@ enum EventCode {
Tick = 0x80000007,
BarStateUpdate = 0x80000014,
Input = 0x80000015,
Lua = 0x8000001d,
Scroller = 0x8000001e,
Trails = 0x8000001f,
Unknown = 999,
};

Expand Down Expand Up @@ -67,6 +78,7 @@ class I3Ipc: public QObject {
explicit I3Ipc(const QList<QString>& events);

[[nodiscard]] QString socketPath() const;
[[nodiscard]] QString compositor() const;

void makeRequest(const QByteArray& request);
void dispatch(const QString& payload);
Expand Down Expand Up @@ -101,6 +113,7 @@ protected slots:

private:
QList<QString> mEvents;
QString mCompositor;
};

} // namespace qs::i3::ipc
91 changes: 90 additions & 1 deletion src/x11/i3/ipc/controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
#include "connection.hpp"
#include "monitor.hpp"
#include "workspace.hpp"
#include "scroller.hpp"
#include "window.hpp"

namespace qs::i3::ipc {

Expand All @@ -31,7 +33,7 @@ QS_LOGGING_CATEGORY(logI3Ipc, "quickshell.I3.ipc", QtWarningMsg);
QS_LOGGING_CATEGORY(logI3IpcEvents, "quickshell.I3.ipc.events", QtWarningMsg);
} // namespace

I3IpcController::I3IpcController(): I3Ipc({"workspace", "output"}) {
I3IpcController::I3IpcController(): I3Ipc({"workspace", "output", "mode", "window"}) {
// bind focused workspace to focused monitor's active workspace
this->bFocusedWorkspace.setBinding([this]() -> I3Workspace* {
if (!this->bFocusedMonitor) return nullptr;
Expand All @@ -49,6 +51,13 @@ void I3IpcController::onConnected() {
// detected on launch.
this->refreshWorkspaces();
this->refreshMonitors();
this->refreshBindingModes();
this->bFocusedWindow = new I3Window(this);
if (this->compositor() == "scroll") {
this->bFocusedScroller = new I3Scroller(this);
this->refreshScroller();
this->refreshTrails();
}
}

void I3IpcController::setFocusedMonitor(I3Monitor* monitor) {
Expand Down Expand Up @@ -198,6 +207,76 @@ void I3IpcController::handleGetOutputsEvent(I3IpcEvent* event) {
}
}

void I3IpcController::refreshBindingModes() {
this->makeRequest(I3Ipc::buildRequestMessage(EventCode::GetBindingState));
this->makeRequest(I3Ipc::buildRequestMessage(EventCode::GetBindingModes));
}

void I3IpcController::handleGetBindingModesEvent(I3IpcEvent* event) {
auto data = event->mData;
auto modes = data.array();
for (auto mode: modes) {
auto name = mode.toString();
this->mBindingModes.push_back(name);
}
}

void I3IpcController::handleGetBindingStateEvent(I3IpcEvent* event) {
auto data = event->mData;
this->bActiveBindingMode = data["name"].toString();
}

void I3IpcController::handleModeEvent(I3IpcEvent* event) {
auto data = event->mData;
this->bActiveBindingMode = data["change"].toString();
}

void I3IpcController::refreshScroller() {
if (this->compositor() == "scroll") {
this->makeRequest(I3Ipc::buildRequestMessage(EventCode::GetScroller));
}
}

void I3IpcController::handleGetScrollerEvent(I3IpcEvent* event) {
if (this->compositor() == "scroll") {
auto scroller = event->mData["scroller"].toObject();
this->bFocusedScroller->updateFromObject(scroller.toVariantMap());
}
}

void I3IpcController::handleScrollerEvent(I3IpcEvent* event) {
this->handleGetScrollerEvent(event);
}

void I3IpcController::handleWindowEvent(I3IpcEvent* event) {
this->bFocusedWindow->updateFromObject(event->mData.object().toVariantMap());
}

void I3IpcController::refreshTrails() {
if (this->compositor() == "scroll") {
this->makeRequest(I3Ipc::buildRequestMessage(EventCode::GetTrails));
}
}

void I3IpcController::handleGetTrailsEvent(I3IpcEvent* event) {
if (this->compositor() == "scroll") {
auto trails = event->mData["trails"];
this->bNumberOfTrails = trails["length"].toInt();
this->bActiveTrail = trails["active"].toInt();
this->bActiveTrailLength = trails["trail_length"].toInt();
}
}

void I3IpcController::handleTrailsEvent(I3IpcEvent* event) {
this->handleGetTrailsEvent(event);
}

void I3IpcController::handleLuaEvent(I3IpcEvent* event) {
if (this->compositor() == "scroll") {
this->bLuaData = event->mData.toJson(QJsonDocument::Compact);
}
}

void I3IpcController::onEvent(I3IpcEvent* event) {
switch (event->mCode) {
case EventCode::Workspace: this->handleWorkspaceEvent(event); return;
Expand All @@ -209,7 +288,16 @@ void I3IpcController::onEvent(I3IpcEvent* event) {
case EventCode::Subscribe: qCInfo(logI3Ipc) << "Connected to IPC"; return;
case EventCode::GetOutputs: this->handleGetOutputsEvent(event); return;
case EventCode::GetWorkspaces: this->handleGetWorkspacesEvent(event); return;
case EventCode::GetBindingModes: this->handleGetBindingModesEvent(event); return;
case EventCode::GetBindingState: this->handleGetBindingStateEvent(event); return;
case EventCode::GetScroller: this->handleGetScrollerEvent(event); return;
case EventCode::GetTrails: this->handleGetTrailsEvent(event); return;
case EventCode::RunCommand: I3IpcController::handleRunCommand(event); return;
case EventCode::Mode: this->handleModeEvent(event); return;
case EventCode::Window: this->handleWindowEvent(event); return;
case EventCode::Lua: this->handleLuaEvent(event); return;
case EventCode::Scroller: this->handleScrollerEvent(event); return;
case EventCode::Trails: this->handleTrailsEvent(event); return;
case EventCode::Unknown:
qCWarning(logI3Ipc) << "Unknown event:" << event->type() << event->data();
return;
Expand Down Expand Up @@ -359,6 +447,7 @@ I3Monitor* I3IpcController::findMonitorByName(const QString& name, bool createIf

ObjectModel<I3Monitor>* I3IpcController::monitors() { return &this->mMonitors; }
ObjectModel<I3Workspace>* I3IpcController::workspaces() { return &this->mWorkspaces; }
QVector<QString>* I3IpcController::bindingModes() { return &this->mBindingModes; }

bool I3IpcController::compareWorkspaces(I3Workspace* a, I3Workspace* b) {
return a->bindableNumber().value() > b->bindableNumber().value();
Expand Down
Loading