Skip to content

Commit

Permalink
i3/sway: fix review
Browse files Browse the repository at this point in the history
  • Loading branch information
nydragon committed Nov 10, 2024
1 parent d54fe49 commit 84d6d97
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 49 deletions.
12 changes: 11 additions & 1 deletion BUILD.md
Original file line number Diff line number Diff line change
Expand Up @@ -174,13 +174,23 @@ To disable: `-DHYPRLAND_GLOBAL_SHORTCUTS=OFF`
[hyprland-global-shortcuts-v1]: https://github.com/hyprwm/hyprland-protocols/blob/main/protocols/hyprland-global-shortcuts-v1.xml

#### Hyprland Focus Grab
Enables windows to grab focus similarly to a context menu undr hyprland through the
Enables windows to grab focus similarly to a context menu under hyprland through the
[hyprland-focus-grab-v1] protocol. This feature has no extra dependencies.

To disable: `-DHYPRLAND_FOCUS_GRAB=OFF`

[hyprland-focus-grab-v1]: https://github.com/hyprwm/hyprland-protocols/blob/main/protocols/hyprland-focus-grab-v1.xml

### i3/Sway
Enables i3 and Sway specific features, does not have any dependency on Wayland or x11.

To disable: `-DI3=OFF`

#### i3/Sway IPC
Enables interfacing with i3 and Sway's IPC.

To disable: `-DI3_IPC=OFF`

## Building
*For developers and prospective contributors: See [CONTRIBUTING.md](CONTRIBUTING.md).*

Expand Down
2 changes: 1 addition & 1 deletion src/x11/i3/ipc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ qt_add_library(quickshell-i3-ipc STATIC
qt_add_qml_module(quickshell-i3-ipc
URI Quickshell.I3._Ipc
VERSION 0.1
DEPENDENCIES QtQml Quickshell
DEPENDENCIES QtQml
)

qs_add_module_deps_light(quickshell-i3-ipc Quickshell)
Expand Down
88 changes: 42 additions & 46 deletions src/x11/i3/ipc/connection.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#include <algorithm>
#include <cstring>
#include <tuple>

#include <bit>
#include <qbytearray.h>
#include <qbytearrayview.h>
#include <qcontainerfwd.h>
Expand All @@ -25,8 +25,8 @@
#include "monitor.hpp"
#include "workspace.hpp"

Q_LOGGING_CATEGORY(logi3Ipc, "quickshell.I3.ipc", QtWarningMsg);
Q_LOGGING_CATEGORY(logi3IpcEvents, "quickshell.I3.ipc.events", QtWarningMsg);
Q_LOGGING_CATEGORY(logI3Ipc, "quickshell.I3.ipc", QtWarningMsg);
Q_LOGGING_CATEGORY(logI3IpcEvents, "quickshell.I3.ipc.events", QtWarningMsg);

namespace qs::i3::ipc {

Expand All @@ -38,7 +38,7 @@ QVector<Event> I3Ipc::makeRequest(const QByteArray& request) {
auto dataRaw = this->commandSocket.readAll();
return I3Ipc::parseResponse(dataRaw);
} else {
qWarning(logi3Ipc) << "Timeout while waiting for read for" << request;
qCWarning(logI3Ipc) << "Timeout while waiting for read for" << request;
return {};
}
}
Expand All @@ -49,7 +49,7 @@ void I3Ipc::dispatch(const QString& payload) {
QVector<Event> res = this->makeRequest(message);

if (res.isEmpty()) {
qWarning() << "IPC did not reply, error while executing" << payload;
qCWarning(logI3Ipc) << "IPC did not reply, error while executing" << payload;
}

auto [_, data] = res.first();
Expand All @@ -59,35 +59,31 @@ void I3Ipc::dispatch(const QString& payload) {
const bool success = jsonMessage["success"].toBool();

if (!success) {
qWarning() << "Error while executing dispatch of" << payload << ":\n\t"
<< jsonMessage["error"];
qCWarning(logI3Ipc) << "Error while executing dispatch of" << payload << ":\n\t"
<< jsonMessage["error"];
}
}
}

QByteArray I3Ipc::buildRequestMessage(EventCode cmd, const QByteArray& payload) {
int len = static_cast<int>(payload.length());
QByteArray lenBytes = QByteArray(4, Qt::Initialization::Uninitialized);
QByteArray typeBytes = QByteArray(4, Qt::Initialization::Uninitialized);
auto payloadLength = static_cast<quint32>(payload.length());

std::memcpy(lenBytes.data(), &len, 4);
std::memcpy(typeBytes.data(), &cmd, 4);
auto type = QByteArray(std::bit_cast<std::array<char, 4>>(cmd).data(), 4);
auto len = QByteArray(std::bit_cast<std::array<char, 4>>(payloadLength).data(), 4);

QByteArray data = QByteArray(MAGIC.data()) + lenBytes + typeBytes + payload;

return data;
return MAGIC.data() + len + type + payload;
}

I3Ipc::I3Ipc() {
auto sock = qEnvironmentVariable("I3SOCK");

if (sock.isEmpty()) {
qWarning() << "$I3SOCK is unset. Trying $SWAYSOCK Cannot connect to I3.";
qCWarning(logI3Ipc) << "$I3SOCK is unset. Trying $SWAYSOCK.";

sock = qEnvironmentVariable("SWAYSOCK");

if (sock.isEmpty()) {
qWarning() << "$SWAYSOCK and I3SOCK are unset. Cannot connect to socket.";
qCWarning(logI3Ipc) << "$SWAYSOCK and I3SOCK are unset. Cannot connect to socket.";
return;
}
}
Expand Down Expand Up @@ -154,7 +150,7 @@ QVector<Event> I3Ipc::parseResponse(QByteArray rawEvent) {
ds >> type;

if (I3IpcEvent::intToEvent(type) == EventCode::UNKNOWN) {
qWarning(logi3Ipc) << "Received unknown event" << rawEvent;
qCWarning(logI3Ipc) << "Received unknown event" << rawEvent;
return events;
}

Expand All @@ -165,7 +161,7 @@ QVector<Event> I3Ipc::parseResponse(QByteArray rawEvent) {
auto data = QJsonDocument::fromJson(byteData, &e);

if (e.error != QJsonParseError::NoError) {
qWarning(logi3Ipc) << "Invalid JSON value:" << e.errorString() << "\n\t" << byteData;
qCWarning(logI3Ipc) << "Invalid JSON value:" << e.errorString() << "\n\t" << byteData;
} else {
events.push_back(std::tuple(I3IpcEvent::intToEvent(type), data));
}
Expand All @@ -178,18 +174,18 @@ QVector<Event> I3Ipc::parseResponse(QByteArray rawEvent) {

void I3Ipc::eventSocketError(QLocalSocket::LocalSocketError error) const {
if (!this->valid) {
qWarning() << "Unable to connect to I3 socket:" << error;
qCWarning(logI3Ipc) << "Unable to connect to I3 socket:" << error;
} else {
qWarning() << "I3 socket error:" << error;
qCWarning(logI3Ipc) << "I3 socket error:" << error;
}
}

void I3Ipc::eventSocketStateChanged(QLocalSocket::LocalSocketState state) {
if (state == QLocalSocket::ConnectedState) {
qCInfo(logi3Ipc) << "I3 event socket connected.";
qCInfo(logI3Ipc) << "I3 event socket connected.";
emit this->connected();
} else if (state == QLocalSocket::UnconnectedState && this->valid) {
qCWarning(logi3Ipc) << "I3 event socket disconnected.";
qCWarning(logI3Ipc) << "I3 event socket disconnected.";
}

this->valid = state == QLocalSocket::ConnectedState;
Expand Down Expand Up @@ -255,7 +251,7 @@ void I3Ipc::refreshWorkspaces() {
auto res = this->makeRequest(msg);

if (res.isEmpty()) {
qWarning(logi3Ipc) << "Failed updating workspaces";
qCWarning(logI3Ipc) << "Failed updating workspaces";
return;
}

Expand All @@ -266,7 +262,7 @@ void I3Ipc::refreshWorkspaces() {
const auto& mList = this->mWorkspaces.valueList();
auto names = QVector<QString>();

qInfo(logi3Ipc) << "There are" << workspaces.toVariantList().length() << "workspaces";
qCDebug(logI3Ipc) << "There are" << workspaces.toVariantList().length() << "workspaces";
for (auto entry: workspaces) {
auto object = entry.toObject().toVariantMap();
auto name = object["name"].toString();
Expand Down Expand Up @@ -303,7 +299,7 @@ void I3Ipc::refreshWorkspaces() {
}
}

qInfo(logi3Ipc) << "Removing" << removedWorkspaces.length() << "deleted workspaces.";
qCDebug(logI3Ipc) << "Removing" << removedWorkspaces.length() << "deleted workspaces.";

for (auto* workspace: removedWorkspaces) {
this->mWorkspaces.removeObject(workspace);
Expand All @@ -316,7 +312,7 @@ void I3Ipc::refreshMonitors() {
auto res = this->makeRequest(msg);

if (res.isEmpty()) {
qWarning(logi3Ipc) << "Failed to update monitors";
qCWarning(logI3Ipc) << "Failed to update monitors";
return;
}

Expand All @@ -326,7 +322,7 @@ void I3Ipc::refreshMonitors() {
const auto& mList = this->mMonitors.valueList();
auto names = QVector<QString>();

qInfo(logi3Ipc) << "There are" << monitors.toVariantList().length() << "monitors";
qCDebug(logI3Ipc) << "There are" << monitors.toVariantList().length() << "monitors";

for (auto elem: monitors) {
auto object = elem.toObject().toVariantMap();
Expand Down Expand Up @@ -364,7 +360,7 @@ void I3Ipc::refreshMonitors() {
}
}

qInfo(logi3Ipc) << "Removing" << removedMonitors.length() << "disconnected monitors.";
qCDebug(logI3Ipc) << "Removing" << removedMonitors.length() << "disconnected monitors.";

for (auto* monitor: removedMonitors) {
this->mMonitors.removeObject(monitor);
Expand All @@ -377,14 +373,14 @@ void I3Ipc::onEvent(I3IpcEvent* event) {
case EventCode::WORKSPACE: this->handleWorkspaceEvent(event); return;
case EventCode::OUTPUT:
/// I3 only sends an "unspecified" event, so we have to query the data changes ourselves
qInfo(logi3Ipc) << "Refreshing Monitors...";
qCInfo(logI3Ipc) << "Refreshing Monitors...";
this->refreshMonitors();
return;
case EventCode::SUBSCRIBE: qInfo(logi3Ipc) << "Connected to IPC"; return;
case EventCode::SUBSCRIBE: qCInfo(logI3Ipc) << "Connected to IPC"; return;
case EventCode::UNKNOWN:
qWarning(logi3Ipc) << "Unknown event:" << event->type() << event->data();
qCWarning(logI3Ipc) << "Unknown event:" << event->type() << event->data();
return;
default: qWarning(logi3Ipc) << "Unhandled event:" << event->type();
default: qCWarning(logI3Ipc) << "Unhandled event:" << event->type();
}
}

Expand All @@ -394,7 +390,7 @@ void I3Ipc::handleWorkspaceEvent(I3IpcEvent* event) {
auto change = event->mData["change"];

if (change == "init") {
qCInfo(logi3IpcEvents) << "New workspace has been created";
qCInfo(logI3IpcEvents) << "New workspace has been created";

auto workspaceData = event->mData["current"];

Expand All @@ -405,13 +401,13 @@ void I3Ipc::handleWorkspaceEvent(I3IpcEvent* event) {
}

this->mWorkspaces.insertObject(workspace);
qCInfo(logi3Ipc) << "Added workspace to list";
qCInfo(logI3Ipc) << "Added workspace to list";

} else if (change == "focus") {
auto oldName = event->mData["old"]["name"].toString();
auto newName = event->mData["current"]["name"].toString();

qCInfo(logi3IpcEvents) << "Focus changed: " << oldName << "->" << newName;
qCInfo(logI3IpcEvents) << "Focus changed: " << oldName << "->" << newName;

auto* oldWorkspace = this->findWorkspaceByName(oldName);
auto* newWorkspace = this->findWorkspaceByName(newName);
Expand All @@ -431,7 +427,7 @@ void I3Ipc::handleWorkspaceEvent(I3IpcEvent* event) {
auto* oldWorkspace = this->findWorkspaceByName(name);

if (oldWorkspace != nullptr) {
qCInfo(logi3Ipc) << "Deleting" << oldWorkspace->id() << name;
qCInfo(logI3Ipc) << "Deleting" << oldWorkspace->id() << name;

if (this->mFocusedWorkspace == oldWorkspace) {
this->setFocusedWorkspace(nullptr);
Expand All @@ -441,7 +437,7 @@ void I3Ipc::handleWorkspaceEvent(I3IpcEvent* event) {

delete oldWorkspace;
} else {
qCInfo(logi3Ipc) << "Workspace" << name << "has already been deleted";
qCInfo(logI3Ipc) << "Workspace" << name << "has already been deleted";
}
} else if (change == "move" || change == "rename" || change == "urgent") {
auto name = event->mData["current"]["name"].toString();
Expand All @@ -453,10 +449,10 @@ void I3Ipc::handleWorkspaceEvent(I3IpcEvent* event) {

workspace->updateFromObject(data);
} else {
qWarning() << "Workspace" << name << "doesn't exist";
qCWarning(logI3Ipc) << "Workspace" << name << "doesn't exist";
}
} else if (change == "reload") {
qInfo(logi3Ipc) << "Refreshing Workspaces...";
qCInfo(logI3Ipc) << "Refreshing Workspaces...";
this->refreshWorkspaces();
}
}
Expand All @@ -468,21 +464,21 @@ I3Monitor* I3Ipc::monitorFor(QuickshellScreenInfo* screen) {
}

I3Workspace* I3Ipc::findWorkspaceByName(const QString& name) {
auto mList = this->mWorkspaces.valueList();
auto workspaceIter = std::find_if(mList.begin(), mList.end(), [name](const I3Workspace* m) {
auto list = this->mWorkspaces.valueList();
auto workspaceIter = std::find_if(list.begin(), list.end(), [name](const I3Workspace* m) {
return m->name() == name;
});

return workspaceIter == mList.end() ? nullptr : *workspaceIter;
return workspaceIter == list.end() ? nullptr : *workspaceIter;
}

I3Monitor* I3Ipc::findMonitorByName(const QString& name) {
auto mList = this->mMonitors.valueList();
auto monitorIter = std::find_if(mList.begin(), mList.end(), [name](const I3Monitor* m) {
auto list = this->mMonitors.valueList();
auto monitorIter = std::find_if(list.begin(), list.end(), [name](const I3Monitor* m) {
return m->name() == name;
});

return monitorIter == mList.end() ? nullptr : *monitorIter;
return monitorIter == list.end() ? nullptr : *monitorIter;
}

ObjectModel<I3Monitor>* I3Ipc::monitors() { return &this->mMonitors; }
Expand Down
2 changes: 1 addition & 1 deletion src/x11/i3/ipc/qml.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class I3IpcQml: public QObject {
public:
explicit I3IpcQml();

/// Execute an I3/Sway command [man 5 sway](https://man.archlinux.org/man/sway.5.en#COMMANDS)
/// Execute an [I3/Sway command](https://i3wm.org/docs/userguide.html#list_of_commands)
Q_INVOKABLE static void dispatch(const QString& request);

/// Refresh monitor information.
Expand Down

0 comments on commit 84d6d97

Please sign in to comment.