cleanup for hyprland lua configs

This commit is contained in:
2026-05-20 06:50:14 +02:00
parent ceca949535
commit 96bf5f3365
5 changed files with 194 additions and 176 deletions
+11 -2
View File
@@ -3,6 +3,7 @@ pragma ComponentBehavior: Bound
import Quickshell import Quickshell
import Quickshell.Io import Quickshell.Io
import Quickshell.Hyprland
import QtQuick import QtQuick
import ZShell import ZShell
import qs.Helpers import qs.Helpers
@@ -79,8 +80,8 @@ Singleton {
} }
function reloadHyprRules(): void { function reloadHyprRules(): void {
const barStr = "keyword layerrule %1 %2, match:namespace ZShell-Bar"; const barStr = Hyprland.usingLua ? `eval 'hl.layer_rule({ match = { namespace = "ZShell-Bar" }, %1 = true, %2 = true })'` : "keyword layerrule %1 %2, match:namespace ZShell-Bar";
const authStr = "keyword layerrule %1 %2, match:namespace ZShell-Auth"; const authStr = Hyprland.usingLua ? `eval 'hl.layer_rule({ match = { namespace = "ZShell-Auth" }, %1 = true, %2 = true })'` : "keyword layerrule %1 %2, match:namespace ZShell-Auth";
Hypr.extras.batchMessage([barStr.arg("blur").arg(transparency.enabled ? 1 : 0), barStr.arg("ignore_alpha").arg(transparency.base - 0.03)]); Hypr.extras.batchMessage([barStr.arg("blur").arg(transparency.enabled ? 1 : 0), barStr.arg("ignore_alpha").arg(transparency.base - 0.03)]);
Hypr.extras.batchMessage([authStr.arg("blur").arg(transparency.enabled ? 1 : 0), authStr.arg("ignore_alpha").arg(transparency.base - 0.03)]); Hypr.extras.batchMessage([authStr.arg("blur").arg(transparency.enabled ? 1 : 0), authStr.arg("ignore_alpha").arg(transparency.base - 0.03)]);
} }
@@ -93,6 +94,14 @@ Singleton {
Component.onCompleted: debounceTimer.triggered() Component.onCompleted: debounceTimer.triggered()
Connections {
function onUsingLuaChanged(): void {
root.reloadHyprRules();
}
target: Hyprland
}
Connections { Connections {
function onConfigReloaded(): void { function onConfigReloaded(): void {
root.reloadHyprRules(); root.reloadHyprRules();
+1 -1
View File
@@ -279,7 +279,7 @@ Variants {
deformAmount: 0.08 deformAmount: 0.08
implicitHeight: panels.settings.height * (1 + extraHeight) implicitHeight: panels.settings.height * (1 + extraHeight)
implicitWidth: panels.settings.width implicitWidth: panels.settings.width
panel: panels.settings panel: panels.settingsWrapper
radius: Appearance.rounding.large radius: Appearance.rounding.large
topLeftRadius: Appearance.rounding.large + Appearance.padding.smaller topLeftRadius: Appearance.rounding.large + Appearance.padding.smaller
topRightRadius: Appearance.rounding.large + Appearance.padding.smaller topRightRadius: Appearance.rounding.large + Appearance.padding.smaller
+2 -1
View File
@@ -79,7 +79,8 @@ Item {
} }
onPressed: { onPressed: {
Hyprland.dispatch(`workspace ${button.modelData.name}`); const ws = button.modelData.name;
Hyprland.dispatch(Hyprland.usingLua ? `hl.dsp.focus({ workspace= "${ws}"})` : `workspace ${ws}`);
} }
} }
} }
+146 -142
View File
@@ -1,217 +1,221 @@
#include "hyprextras.hpp" #include "hyprextras.hpp"
#include "hyprdevices.hpp"
#include <qdir.h> #include <qdir.h>
#include <qjsonarray.h> #include <qjsonarray.h>
#include <qlocalsocket.h> #include <qlocalsocket.h>
#include <qloggingcategory.h>
#include <qvariant.h> #include <qvariant.h>
Q_LOGGING_CATEGORY(lcHypr, "ZShell.internal.hypr", QtInfoMsg)
namespace ZShell::internal::hypr { namespace ZShell::internal::hypr {
HyprExtras::HyprExtras(QObject* parent) HyprExtras::HyprExtras(QObject* parent)
: QObject(parent) : QObject(parent)
, m_requestSocket("") , m_requestSocket("")
, m_eventSocket("") , m_eventSocket("")
, m_socket(nullptr) , m_socket(nullptr)
, m_socketValid(false) , m_socketValid(false)
, m_devices(new HyprDevices(this)) { , m_devices(new HyprDevices(this)) {
const auto his = qEnvironmentVariable("HYPRLAND_INSTANCE_SIGNATURE"); const auto his = qEnvironmentVariable("HYPRLAND_INSTANCE_SIGNATURE");
if (his.isEmpty()) { if (his.isEmpty()) {
qWarning() qCWarning(lcHypr) << "$HYPRLAND_INSTANCE_SIGNATURE is unset. Unable to connect to Hyprland socket.";
<< "HyprExtras::HyprExtras: $HYPRLAND_INSTANCE_SIGNATURE is unset. Unable to connect to Hyprland socket."; return;
return; }
}
auto hyprDir = QString("%1/hypr/%2").arg(qEnvironmentVariable("XDG_RUNTIME_DIR"), his); auto hyprDir = QString("%1/hypr/%2").arg(qEnvironmentVariable("XDG_RUNTIME_DIR"), his);
if (!QDir(hyprDir).exists()) { if (!QDir(hyprDir).exists()) {
hyprDir = "/tmp/hypr/" + his; hyprDir = "/tmp/hypr/" + his;
if (!QDir(hyprDir).exists()) { if (!QDir(hyprDir).exists()) {
qWarning() << "HyprExtras::HyprExtras: Hyprland socket directory does not exist. Unable to connect to " qCWarning(lcHypr) << "Hyprland socket directory does not exist. Unable to connect to Hyprland socket.";
"Hyprland socket."; return;
return; }
} }
}
m_requestSocket = hyprDir + "/.socket.sock"; m_requestSocket = hyprDir + "/.socket.sock";
m_eventSocket = hyprDir + "/.socket2.sock"; m_eventSocket = hyprDir + "/.socket2.sock";
refreshOptions(); refreshOptions();
refreshDevices(); refreshDevices();
m_socket = new QLocalSocket(this); m_socket = new QLocalSocket(this);
QObject::connect(m_socket, &QLocalSocket::errorOccurred, this, &HyprExtras::socketError); QObject::connect(m_socket, &QLocalSocket::errorOccurred, this, &HyprExtras::socketError);
QObject::connect(m_socket, &QLocalSocket::stateChanged, this, &HyprExtras::socketStateChanged); QObject::connect(m_socket, &QLocalSocket::stateChanged, this, &HyprExtras::socketStateChanged);
QObject::connect(m_socket, &QLocalSocket::readyRead, this, &HyprExtras::readEvent); QObject::connect(m_socket, &QLocalSocket::readyRead, this, &HyprExtras::readEvent);
m_socket->connectToServer(m_eventSocket, QLocalSocket::ReadOnly); m_socket->connectToServer(m_eventSocket, QLocalSocket::ReadOnly);
} }
QVariantHash HyprExtras::options() const { QVariantHash HyprExtras::options() const {
return m_options; return m_options;
} }
HyprDevices* HyprExtras::devices() const { HyprDevices* HyprExtras::devices() const {
return m_devices; return m_devices;
} }
void HyprExtras::message(const QString& message) { void HyprExtras::message(const QString& message) {
if (message.isEmpty()) { if (message.isEmpty()) {
return; return;
} }
makeRequest(message, [](bool success, const QByteArray& res) { makeRequest(message, [](bool success, const QByteArray& res) {
if (!success) { if (!success) {
qWarning() << "HyprExtras::message: request error:" << QString::fromUtf8(res); qCWarning(lcHypr) << "message: request error:" << QString::fromUtf8(res);
} }
}); });
} }
void HyprExtras::batchMessage(const QStringList& messages) { void HyprExtras::batchMessage(const QStringList& messages) {
if (messages.isEmpty()) { if (messages.isEmpty()) {
return; return;
} }
makeRequest("[[BATCH]]" + messages.join(";"), [](bool success, const QByteArray& res) { makeRequest("[[BATCH]]" + messages.join(";"), [](bool success, const QByteArray& res) {
if (!success) { if (!success) {
qWarning() << "HyprExtras::batchMessage: request error:" << QString::fromUtf8(res); qCWarning(lcHypr) << "batchMessage: request error:" << QString::fromUtf8(res);
} }
}); });
} }
void HyprExtras::applyOptions(const QVariantHash& options) { void HyprExtras::applyOptions(const QVariantHash& options) {
if (options.isEmpty()) { if (options.isEmpty()) {
return; return;
} }
QString request = "[[BATCH]]"; QString request;
for (auto it = options.constBegin(); it != options.constEnd(); ++it) { request.reserve(12 + options.size() * 40);
request += QString("keyword %1 %2;").arg(it.key(), it.value().toString()); request += QLatin1String("[[BATCH]]");
} for (auto it = options.constBegin(); it != options.constEnd(); ++it) {
request += QLatin1String("keyword ") + it.key() + QLatin1Char(' ') + it.value().toString() + QLatin1Char(';');
}
makeRequest(request, [this](bool success, const QByteArray& res) { makeRequest(request, [this](bool success, const QByteArray& res) {
if (success) { if (success) {
refreshOptions(); refreshOptions();
} else { } else {
qWarning() << "HyprExtras::applyOptions: request error" << QString::fromUtf8(res); qCWarning(lcHypr) << "applyOptions: request error" << QString::fromUtf8(res);
} }
}); });
} }
void HyprExtras::refreshOptions() { void HyprExtras::refreshOptions() {
if (!m_optionsRefresh.isNull()) { if (!m_optionsRefresh.isNull()) {
m_optionsRefresh->close(); m_optionsRefresh->close();
} }
m_optionsRefresh = makeRequestJson("descriptions", [this](bool success, const QJsonDocument& response) { m_optionsRefresh = makeRequestJson("descriptions", [this](bool success, const QJsonDocument& response) {
m_optionsRefresh.reset(); m_optionsRefresh.reset();
if (!success) { if (!success) {
return; return;
} }
const auto options = response.array(); const auto options = response.array();
bool dirty = false; bool dirty = false;
for (const auto& o : std::as_const(options)) { for (const auto& o : std::as_const(options)) {
const auto obj = o.toObject(); const auto obj = o.toObject();
const auto key = obj.value("value").toString(); const auto key = obj.value("value").toString();
const auto value = obj.value("data").toObject().value("current").toVariant(); const auto value = obj.value("data").toObject().value("current").toVariant();
if (m_options.value(key) != value) { if (m_options.value(key) != value) {
dirty = true; dirty = true;
m_options.insert(key, value); m_options.insert(key, value);
} }
} }
if (dirty) { if (dirty) {
emit optionsChanged(); emit optionsChanged();
} }
}); });
} }
void HyprExtras::refreshDevices() { void HyprExtras::refreshDevices() {
if (!m_devicesRefresh.isNull()) { if (!m_devicesRefresh.isNull()) {
m_devicesRefresh->close(); m_devicesRefresh->close();
} }
m_devicesRefresh = makeRequestJson("devices", [this](bool success, const QJsonDocument& response) { m_devicesRefresh = makeRequestJson("devices", [this](bool success, const QJsonDocument& response) {
m_devicesRefresh.reset(); m_devicesRefresh.reset();
if (success) { if (success) {
m_devices->updateLastIpcObject(response.object()); m_devices->updateLastIpcObject(response.object());
} }
}); });
} }
void HyprExtras::socketError(QLocalSocket::LocalSocketError error) const { void HyprExtras::socketError(QLocalSocket::LocalSocketError error) const {
if (!m_socketValid) { if (!m_socketValid) {
qWarning() << "HyprExtras::socketError: unable to connect to Hyprland event socket:" << error; qCWarning(lcHypr) << "socketError: unable to connect to Hyprland event socket:" << error;
} else { } else {
qWarning() << "HyprExtras::socketError: Hyprland event socket error:" << error; qCWarning(lcHypr) << "socketError: Hyprland event socket error:" << error;
} }
} }
void HyprExtras::socketStateChanged(QLocalSocket::LocalSocketState state) { void HyprExtras::socketStateChanged(QLocalSocket::LocalSocketState state) {
if (state == QLocalSocket::UnconnectedState && m_socketValid) { if (state == QLocalSocket::UnconnectedState && m_socketValid) {
qWarning() << "HyprExtras::socketStateChanged: Hyprland event socket disconnected."; qCWarning(lcHypr) << "socketStateChanged: Hyprland event socket disconnected.";
} }
m_socketValid = state == QLocalSocket::ConnectedState; m_socketValid = state == QLocalSocket::ConnectedState;
} }
void HyprExtras::readEvent() { void HyprExtras::readEvent() {
while (true) { while (true) {
auto rawEvent = m_socket->readLine(); auto rawEvent = m_socket->readLine();
if (rawEvent.isEmpty()) { if (rawEvent.isEmpty()) {
break; break;
} }
rawEvent.truncate(rawEvent.length() - 1); // Remove trailing \n rawEvent.truncate(rawEvent.length() - 1); // Remove trailing \n
const auto event = QByteArrayView(rawEvent.data(), rawEvent.indexOf(">>")); const auto event = QByteArrayView(rawEvent.data(), rawEvent.indexOf(">>"));
handleEvent(QString::fromUtf8(event)); handleEvent(QString::fromUtf8(event));
} }
} }
void HyprExtras::handleEvent(const QString& event) { void HyprExtras::handleEvent(const QString& event) {
if (event == "configreloaded") { if (event == "configreloaded") {
refreshOptions(); refreshOptions();
} else if (event == "activelayout") { } else if (event == "activelayout") {
refreshDevices(); refreshDevices();
} }
} }
HyprExtras::SocketPtr HyprExtras::makeRequestJson( HyprExtras::SocketPtr HyprExtras::makeRequestJson(
const QString& request, const std::function<void(bool, QJsonDocument)>& callback) { const QString& request, const std::function<void(bool, QJsonDocument)>& callback) {
return makeRequest("j/" + request, [callback](bool success, const QByteArray& response) { return makeRequest("j/" + request, [callback](bool success, const QByteArray& response) {
callback(success, QJsonDocument::fromJson(response)); callback(success, QJsonDocument::fromJson(response));
}); });
} }
HyprExtras::SocketPtr HyprExtras::makeRequest( HyprExtras::SocketPtr HyprExtras::makeRequest(
const QString& request, const std::function<void(bool, QByteArray)>& callback) { const QString& request, const std::function<void(bool, QByteArray)>& callback) {
if (m_requestSocket.isEmpty()) { if (m_requestSocket.isEmpty()) {
return SocketPtr(); return SocketPtr();
} }
auto socket = SocketPtr::create(this); auto socket = SocketPtr::create(this);
QObject::connect(socket.data(), &QLocalSocket::connected, this, [=, this]() { QObject::connect(socket.data(), &QLocalSocket::connected, this, [=, this]() {
QObject::connect(socket.data(), &QLocalSocket::readyRead, this, [socket, callback]() { QObject::connect(socket.data(), &QLocalSocket::readyRead, this, [socket, callback]() {
const auto response = socket->readAll(); const auto response = socket->readAll();
callback(true, std::move(response)); callback(true, std::move(response));
socket->close(); socket->close();
}); });
socket->write(request.toUtf8()); socket->write(request.toUtf8());
socket->flush(); socket->flush();
}); });
QObject::connect(socket.data(), &QLocalSocket::errorOccurred, this, [=](QLocalSocket::LocalSocketError err) { QObject::connect(socket.data(), &QLocalSocket::errorOccurred, this, [=](QLocalSocket::LocalSocketError err) {
qWarning() << "HyprExtras::makeRequest: error making request:" << err << "| request:" << request; qCWarning(lcHypr) << "makeRequest: error making request:" << err << "| request:" << request;
callback(false, {}); callback(false, {});
socket->close(); socket->close();
}); });
socket->connectToServer(m_requestSocket); socket->connectToServer(m_requestSocket);
return socket; return socket;
} }
} // namespace ZShell::internal::hypr } // namespace ZShell::internal::hypr
+34 -30
View File
@@ -1,56 +1,60 @@
#pragma once #pragma once
#include "hyprdevices.hpp"
#include <qlocalsocket.h> #include <qlocalsocket.h>
#include <qobject.h> #include <qobject.h>
#include <qqmlintegration.h> #include <qqmlintegration.h>
#include <qsharedpointer.h>
#include <qvariant.h>
namespace ZShell::internal::hypr { namespace ZShell::internal::hypr {
class HyprExtras : public QObject { class HyprDevices;
Q_OBJECT
QML_ELEMENT
Q_PROPERTY(QVariantHash options READ options NOTIFY optionsChanged) class HyprExtras : public QObject {
Q_PROPERTY(ZShell::internal::hypr::HyprDevices* devices READ devices CONSTANT) Q_OBJECT
QML_ELEMENT
Q_MOC_INCLUDE("hyprdevices.hpp")
Q_PROPERTY(QVariantHash options READ options NOTIFY optionsChanged)
Q_PROPERTY(ZShell::internal::hypr::HyprDevices* devices READ devices CONSTANT)
public: public:
explicit HyprExtras(QObject* parent = nullptr); explicit HyprExtras(QObject* parent = nullptr);
[[nodiscard]] QVariantHash options() const; [[nodiscard]] QVariantHash options() const;
[[nodiscard]] HyprDevices* devices() const; [[nodiscard]] HyprDevices* devices() const;
Q_INVOKABLE void message(const QString& message); Q_INVOKABLE void message(const QString& message);
Q_INVOKABLE void batchMessage(const QStringList& messages); Q_INVOKABLE void batchMessage(const QStringList& messages);
Q_INVOKABLE void applyOptions(const QVariantHash& options); Q_INVOKABLE void applyOptions(const QVariantHash& options);
Q_INVOKABLE void refreshOptions(); Q_INVOKABLE void refreshOptions();
Q_INVOKABLE void refreshDevices(); Q_INVOKABLE void refreshDevices();
signals: signals:
void optionsChanged(); void optionsChanged();
private: private:
using SocketPtr = QSharedPointer<QLocalSocket>; using SocketPtr = QSharedPointer<QLocalSocket>;
QString m_requestSocket; QString m_requestSocket;
QString m_eventSocket; QString m_eventSocket;
QLocalSocket* m_socket; QLocalSocket* m_socket;
bool m_socketValid; bool m_socketValid;
QVariantHash m_options; QVariantHash m_options;
HyprDevices* const m_devices; HyprDevices* const m_devices;
SocketPtr m_optionsRefresh; SocketPtr m_optionsRefresh;
SocketPtr m_devicesRefresh; SocketPtr m_devicesRefresh;
void socketError(QLocalSocket::LocalSocketError error) const; void socketError(QLocalSocket::LocalSocketError error) const;
void socketStateChanged(QLocalSocket::LocalSocketState state); void socketStateChanged(QLocalSocket::LocalSocketState state);
void readEvent(); void readEvent();
void handleEvent(const QString& event); void handleEvent(const QString& event);
SocketPtr makeRequestJson(const QString& request, const std::function<void(bool, QJsonDocument)>& callback); SocketPtr makeRequestJson(const QString& request, const std::function<void(bool, QJsonDocument)>& callback);
SocketPtr makeRequest(const QString& request, const std::function<void(bool, QByteArray)>& callback); SocketPtr makeRequest(const QString& request, const std::function<void(bool, QByteArray)>& callback);
}; };
} // namespace ZShell::internal::hypr } // namespace ZShell::internal::hypr