diff --git a/Helpers/GameMode.qml b/Helpers/GameMode.qml index 6cbeb68..19b3485 100644 --- a/Helpers/GameMode.qml +++ b/Helpers/GameMode.qml @@ -36,7 +36,7 @@ Singleton { PersistentProperties { id: props - property bool enabled: Hypr.options["animations:enabled"] === 0 + property bool enabled: Hypr.options.animations.enabled === 0 reloadableId: "gamemode" } diff --git a/Helpers/Hypr.qml b/Helpers/Hypr.qml index 2d3eb31..f607b31 100644 --- a/Helpers/Hypr.qml +++ b/Helpers/Hypr.qml @@ -158,6 +158,5 @@ Singleton { HyprExtras { id: extras - } } diff --git a/Helpers/Picker.qml b/Helpers/Picker.qml index 27fc924..55686c2 100644 --- a/Helpers/Picker.qml +++ b/Helpers/Picker.qml @@ -30,8 +30,8 @@ MouseArea { property real ey: screen.height required property LazyLoader loader property bool onClient - property real realBorderWidth: onClient ? (Hypr.options["general:border_size"] ?? 1) : 2 - property real realRounding: onClient ? (Hypr.options["decoration:rounding"] ?? 0) : 0 + property real realBorderWidth: onClient ? (Hypr.options.general.border_size ?? 1) : 2 + property real realRounding: onClient ? (Hypr.options.decoration.rounding ?? 0) : 0 property real rsx: Math.min(sx, ex) property real rsy: Math.min(sy, ey) required property ShellScreen screen diff --git a/Modules/Settings/Categories/Screenshot.qml b/Modules/Settings/Categories/Screenshot.qml index ec7f3a5..260e7f9 100644 --- a/Modules/Settings/Categories/Screenshot.qml +++ b/Modules/Settings/Categories/Screenshot.qml @@ -43,7 +43,7 @@ SettingsPage { } Separator { - visible: Config.screenshot.mode === "manual" + shouldBeActive: Config.screenshot.mode === "manual" } SettingSpinBox { @@ -51,34 +51,34 @@ SettingsPage { name: "Corner radius" object: Config.screenshot setting: "corner_radius" + shouldBeActive: Config.screenshot.mode === "manual" step: 1 - visible: Config.screenshot.mode === "manual" } Separator { - visible: Config.screenshot.mode === "manual" + shouldBeActive: Config.screenshot.mode === "manual" } SettingSwitch { name: "Enable drop shadow" object: Config.screenshot setting: "drop_shadow" - visible: Config.screenshot.mode === "manual" + shouldBeActive: Config.screenshot.mode === "manual" } Separator { - visible: Config.screenshot.mode === "manual" + shouldBeActive: Config.screenshot.mode === "manual" } SettingSwitch { name: "Enable rounded corners" object: Config.screenshot setting: "rounded_corners" - visible: Config.screenshot.mode === "manual" + shouldBeActive: Config.screenshot.mode === "manual" } Separator { - visible: Config.screenshot.mode === "manual" + shouldBeActive: Config.screenshot.mode === "manual" } SettingSpinBox { @@ -86,23 +86,23 @@ SettingsPage { name: "Shadow blur radius" object: Config.screenshot setting: "shadow_blur_radius" + shouldBeActive: Config.screenshot.mode === "manual" step: 1 - visible: Config.screenshot.mode === "manual" } Separator { - visible: Config.screenshot.mode === "manual" + shouldBeActive: Config.screenshot.mode === "manual" } SettingSwitch { name: "Shadow color broken atm" object: Config.Screenshot setting: "shadow_color" - visible: Config.screenshot.mode === "manual" + shouldBeActive: Config.screenshot.mode === "manual" } Separator { - visible: Config.screenshot.mode === "manual" + shouldBeActive: Config.screenshot.mode === "manual" } SettingSpinBox { @@ -110,12 +110,12 @@ SettingsPage { name: "Shadow passes" object: Config.screenshot setting: "shadow_blur_passes" + shouldBeActive: Config.screenshot.mode === "manual" step: 1 - visible: Config.screenshot.mode === "manual" } Separator { - visible: Config.screenshot.mode === "manual" + shouldBeActive: Config.screenshot.mode === "manual" } SettingSpinBox { @@ -123,12 +123,12 @@ SettingsPage { name: "Shadow offset X" object: Config.screenshot setting: "shadow_offset_x" + shouldBeActive: Config.screenshot.mode === "manual" step: 1 - visible: Config.screenshot.mode === "manual" } Separator { - visible: Config.screenshot.mode === "manual" + shouldBeActive: Config.screenshot.mode === "manual" } SettingSpinBox { @@ -136,8 +136,8 @@ SettingsPage { name: "Shadow offset Y" object: Config.screenshot setting: "shadow_offset_y" + shouldBeActive: Config.screenshot.mode === "manual" step: 1 - visible: Config.screenshot.mode === "manual" } } } diff --git a/Plugins/ZShell/Internal/hyprextras.cpp b/Plugins/ZShell/Internal/hyprextras.cpp index 0d372ce..a3056d1 100644 --- a/Plugins/ZShell/Internal/hyprextras.cpp +++ b/Plugins/ZShell/Internal/hyprextras.cpp @@ -1,8 +1,13 @@ #include "hyprextras.hpp" #include "hyprdevices.hpp" +#include +#include + #include #include +#include +#include #include #include #include @@ -163,6 +168,65 @@ static QString buildHlConfigCall(const QString& key, const QVariant& value) { return out; } +static QVariant parseGetOptionValue(const QJsonObject& obj) { + if (obj.contains(QStringLiteral("bool"))) { + return obj.value(QStringLiteral("bool")).toBool(); + } + + if (obj.contains(QStringLiteral("int"))) { + return obj.value(QStringLiteral("int")).toInt(); + } + + if (obj.contains(QStringLiteral("float"))) { + return obj.value(QStringLiteral("float")).toDouble(); + } + + if (obj.contains(QStringLiteral("str"))) { + return obj.value(QStringLiteral("str")).toString(); + } + + if (obj.contains(QStringLiteral("current"))) { + return obj.value(QStringLiteral("current")).toVariant(); + } + + if (obj.contains(QStringLiteral("value"))) { + return obj.value(QStringLiteral("value")).toVariant(); + } + + if (obj.contains(QStringLiteral("data"))) { + const auto data = obj.value(QStringLiteral("data")); + if (data.isObject()) { + const auto d = data.toObject(); + if (d.contains(QStringLiteral("current"))) { + return d.value(QStringLiteral("current")).toVariant(); + } + if (d.contains(QStringLiteral("value"))) { + return d.value(QStringLiteral("value")).toVariant(); + } + } else { + return data.toVariant(); + } + } + + return {}; +} + +static void insertNestedValue(QVariantMap& root, const QStringList& path, const QVariant& value) { + if (path.isEmpty()) { + return; + } + + if (path.size() == 1) { + root.insert(path.first(), value); + return; + } + + const QString head = path.first(); + QVariantMap child = root.value(head).toMap(); + insertNestedValue(child, path.mid(1), value); + root.insert(head, child); +} + } // namespace HyprExtras::HyprExtras(QObject* parent) @@ -203,7 +267,7 @@ HyprExtras::HyprExtras(QObject* parent) m_socket->connectToServer(m_eventSocket, QLocalSocket::ReadOnly); } -QVariantHash HyprExtras::options() const { +QVariantMap HyprExtras::options() const { return m_options; } @@ -269,30 +333,59 @@ void HyprExtras::refreshOptions() { m_optionsRefresh->close(); } - m_optionsRefresh = makeRequestJson(QStringLiteral("descriptions"), [this](bool success, const QJsonDocument& response) { - m_optionsRefresh.reset(); - if (!success) { + ++m_optionsRefreshGeneration; + const quint64 generation = m_optionsRefreshGeneration; + + static const QStringList optionKeys = { + QStringLiteral("general:border_size"), + QStringLiteral("decoration:rounding"), + QStringLiteral("animations:enabled"), + }; + + auto nextOptions = std::make_shared(); + + auto step = std::make_shared >(); + *step = [this, generation, nextOptions, step](int index) { + if (generation != m_optionsRefreshGeneration) { return; } - const auto options = response.array(); - bool dirty = false; - - for (const auto& o : std::as_const(options)) { - const auto obj = o.toObject(); - const auto key = obj.value(QStringLiteral("value")).toString(); - const auto value = obj.value(QStringLiteral("data")).toObject().value(QStringLiteral("current")).toVariant(); - - if (m_options.value(key) != value) { - dirty = true; - m_options.insert(key, value); + if (index >= optionKeys.size()) { + if (m_options != *nextOptions) { + m_options = *nextOptions; + emit optionsChanged(); } + return; } - if (dirty) { - emit optionsChanged(); - } - }); + const QString key = optionKeys.at(index); + + m_optionsRefresh = makeRequestJson( + QStringLiteral("getoption ") + key, + [this, generation, nextOptions, step, index, key](bool success, const QJsonDocument& response) + { + m_optionsRefresh.reset(); + + if (generation != m_optionsRefreshGeneration) { + return; + } + + if (success && response.isObject()) { + const QVariant value = parseGetOptionValue(response.object()); + if (value.isValid()) { + insertNestedValue(*nextOptions, key.split(QLatin1Char(':'), Qt::SkipEmptyParts), value); + } else { + qCWarning(lcHypr) << "refreshOptions: getoption returned no usable value for" << key; + } + } else if (!success) { + qCWarning(lcHypr) << "refreshOptions: getoption request error for" << key; + } + + (*step)(index + 1); + }); + }; + + (*step)(0); } void HyprExtras::refreshDevices() { diff --git a/Plugins/ZShell/Internal/hyprextras.hpp b/Plugins/ZShell/Internal/hyprextras.hpp index fb4ba00..afcac8d 100644 --- a/Plugins/ZShell/Internal/hyprextras.hpp +++ b/Plugins/ZShell/Internal/hyprextras.hpp @@ -1,9 +1,13 @@ #pragma once +#include + +#include #include #include #include #include +#include #include namespace ZShell::internal::hypr { @@ -15,13 +19,13 @@ Q_OBJECT QML_ELEMENT Q_MOC_INCLUDE("hyprdevices.hpp") -Q_PROPERTY(QVariantHash options READ options NOTIFY optionsChanged) +Q_PROPERTY(QVariantMap options READ options NOTIFY optionsChanged) Q_PROPERTY(ZShell::internal::hypr::HyprDevices* devices READ devices CONSTANT) public: explicit HyprExtras(QObject* parent = nullptr); -[[nodiscard]] QVariantHash options() const; +[[nodiscard]] QVariantMap options() const; [[nodiscard]] HyprDevices* devices() const; Q_INVOKABLE void message(const QString& message); @@ -42,11 +46,12 @@ QString m_eventSocket; QLocalSocket* m_socket; bool m_socketValid; -QVariantHash m_options; +QVariantMap m_options; HyprDevices* const m_devices; SocketPtr m_optionsRefresh; SocketPtr m_devicesRefresh; +quint64 m_optionsRefreshGeneration = 0; void socketError(QLocalSocket::LocalSocketError error) const; void socketStateChanged(QLocalSocket::LocalSocketState state);