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
38 changes: 32 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,39 @@ 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::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->mSocketPath = sock;
Expand Down Expand Up @@ -215,4 +239,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
12 changes: 12 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,8 @@ enum EventCode {
Tick = 0x80000007,
BarStateUpdate = 0x80000014,
Input = 0x80000015,
Scroller = 0x8000001e,
Trails = 0x8000001f,
Unknown = 999,
};

Expand Down Expand Up @@ -67,6 +77,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 +112,7 @@ protected slots:

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

} // namespace qs::i3::ipc
84 changes: 83 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,70 @@ 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::onEvent(I3IpcEvent* event) {
switch (event->mCode) {
case EventCode::Workspace: this->handleWorkspaceEvent(event); return;
Expand All @@ -209,7 +282,15 @@ 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::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 +440,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
90 changes: 90 additions & 0 deletions src/x11/i3/ipc/controller.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,14 @@ namespace qs::i3::ipc {

class I3Workspace;
class I3Monitor;
class I3Scroller;
class I3Window;
} // namespace qs::i3::ipc

Q_DECLARE_OPAQUE_POINTER(qs::i3::ipc::I3Workspace*);
Q_DECLARE_OPAQUE_POINTER(qs::i3::ipc::I3Monitor*);
Q_DECLARE_OPAQUE_POINTER(qs::i3::ipc::I3Scroller*);
Q_DECLARE_OPAQUE_POINTER(qs::i3::ipc::I3Window*);

namespace qs::i3::ipc {

Expand All @@ -40,6 +44,9 @@ class I3IpcController: public I3Ipc {

void refreshWorkspaces();
void refreshMonitors();
void refreshBindingModes();
void refreshScroller();
void refreshTrails();

I3Monitor* monitorFor(QuickshellScreenInfo* screen);

Expand All @@ -51,12 +58,43 @@ class I3IpcController: public I3Ipc {
return &this->bFocusedWorkspace;
};

[[nodiscard]] QBindable<QString> bindableActiveBindingMode() const {
return &this->bActiveBindingMode;
};

[[nodiscard]] QBindable<I3Scroller*> bindableFocusedScroller() const {
return &this->bFocusedScroller;
};

[[nodiscard]] QBindable<I3Window*> bindableFocusedWindow() const {
return &this->bFocusedWindow;
};

[[nodiscard]] QBindable<qint32> bindableNumberOfTrails() const {
return &this->bNumberOfTrails;
};

[[nodiscard]] QBindable<qint32> bindableActiveTrail() const {
return &this->bActiveTrail;
};

[[nodiscard]] QBindable<qint32> bindableActiveTrailLength() const {
return &this->bActiveTrailLength;
};

[[nodiscard]] ObjectModel<I3Monitor>* monitors();
[[nodiscard]] ObjectModel<I3Workspace>* workspaces();
[[nodiscard]] QVector<QString>* bindingModes();

signals:
void focusedWorkspaceChanged();
void focusedMonitorChanged();
void activeBindingModeChanged();
void focusedScrollerChanged();
void focusedWindowChanged();
void numberOfTrailsChanged();
void activeTrailChanged();
void activeTrailLengthChanged();

private slots:
void onFocusedMonitorDestroyed();
Expand All @@ -70,12 +108,22 @@ private slots:
void handleWorkspaceEvent(I3IpcEvent* event);
void handleGetWorkspacesEvent(I3IpcEvent* event);
void handleGetOutputsEvent(I3IpcEvent* event);
void handleGetBindingModesEvent(I3IpcEvent* event);
void handleGetBindingStateEvent(I3IpcEvent* event);
void handleModeEvent(I3IpcEvent* event);
void handleGetScrollerEvent(I3IpcEvent* event);
void handleScrollerEvent(I3IpcEvent* event);
void handleGetTrailsEvent(I3IpcEvent* event);
void handleTrailsEvent(I3IpcEvent* event);
void handleWindowEvent(I3IpcEvent* event);
static void handleRunCommand(I3IpcEvent* event);
static bool compareWorkspaces(I3Workspace* a, I3Workspace* b);

ObjectModel<I3Monitor> mMonitors {this};
ObjectModel<I3Workspace> mWorkspaces {this};

QVector<QString> mBindingModes;

Q_OBJECT_BINDABLE_PROPERTY(
I3IpcController,
I3Monitor*,
Expand All @@ -89,6 +137,48 @@ private slots:
bFocusedWorkspace,
&I3IpcController::focusedWorkspaceChanged
);

Q_OBJECT_BINDABLE_PROPERTY(
I3IpcController,
QString,
bActiveBindingMode,
&I3IpcController::activeBindingModeChanged
);

Q_OBJECT_BINDABLE_PROPERTY(
I3IpcController,
I3Scroller*,
bFocusedScroller,
&I3IpcController::focusedScrollerChanged
);

Q_OBJECT_BINDABLE_PROPERTY(
I3IpcController,
I3Window*,
bFocusedWindow,
&I3IpcController::focusedWindowChanged
);

Q_OBJECT_BINDABLE_PROPERTY(
I3IpcController,
qint32,
bNumberOfTrails,
&I3IpcController::numberOfTrailsChanged
);

Q_OBJECT_BINDABLE_PROPERTY(
I3IpcController,
qint32,
bActiveTrail,
&I3IpcController::activeTrailChanged
);

Q_OBJECT_BINDABLE_PROPERTY(
I3IpcController,
qint32,
bActiveTrailLength,
&I3IpcController::activeTrailLengthChanged
);
};

} // namespace qs::i3::ipc
Loading