diff --git a/BUILD.md b/BUILD.md index 5a0652f..834c990 100644 --- a/BUILD.md +++ b/BUILD.md @@ -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).* diff --git a/src/x11/i3/ipc/CMakeLists.txt b/src/x11/i3/ipc/CMakeLists.txt index b7fe264..bde8b80 100644 --- a/src/x11/i3/ipc/CMakeLists.txt +++ b/src/x11/i3/ipc/CMakeLists.txt @@ -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) diff --git a/src/x11/i3/ipc/connection.cpp b/src/x11/i3/ipc/connection.cpp index 8b955d0..2d25c39 100644 --- a/src/x11/i3/ipc/connection.cpp +++ b/src/x11/i3/ipc/connection.cpp @@ -1,7 +1,7 @@ #include -#include #include +#include #include #include #include @@ -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 { @@ -38,7 +38,7 @@ QVector 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 {}; } } @@ -49,7 +49,7 @@ void I3Ipc::dispatch(const QString& payload) { QVector 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(); @@ -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(payload.length()); - QByteArray lenBytes = QByteArray(4, Qt::Initialization::Uninitialized); - QByteArray typeBytes = QByteArray(4, Qt::Initialization::Uninitialized); + auto payloadLength = static_cast(payload.length()); - std::memcpy(lenBytes.data(), &len, 4); - std::memcpy(typeBytes.data(), &cmd, 4); + auto type = QByteArray(std::bit_cast>(cmd).data(), 4); + auto len = QByteArray(std::bit_cast>(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; } } @@ -154,7 +150,7 @@ QVector 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; } @@ -165,7 +161,7 @@ QVector 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)); } @@ -178,18 +174,18 @@ QVector 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; @@ -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; } @@ -266,7 +262,7 @@ void I3Ipc::refreshWorkspaces() { const auto& mList = this->mWorkspaces.valueList(); auto names = QVector(); - 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(); @@ -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); @@ -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; } @@ -326,7 +322,7 @@ void I3Ipc::refreshMonitors() { const auto& mList = this->mMonitors.valueList(); auto names = QVector(); - 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(); @@ -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); @@ -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(); } } @@ -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"]; @@ -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); @@ -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); @@ -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(); @@ -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(); } } @@ -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* I3Ipc::monitors() { return &this->mMonitors; } diff --git a/src/x11/i3/ipc/qml.hpp b/src/x11/i3/ipc/qml.hpp index 868b4c6..585cc65 100644 --- a/src/x11/i3/ipc/qml.hpp +++ b/src/x11/i3/ipc/qml.hpp @@ -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.