3 Commits
Author SHA1 Message Date
zach cbb24a2c40 Merge branch 'main' into feat/fullscreen-reveal-bar
C++ / fmt (pull_request) Successful in 5s
JS/TS / fmt (pull_request) Successful in 15s
JS/TS / lint (pull_request) Successful in 19s
Python / fmt (pull_request) Successful in 31s
Python / lint (pull_request) Successful in 34s
Python / test (pull_request) Successful in 56s
Python / typecheck (pull_request) Successful in 1m23s
Rust / fmt (pull_request) Successful in 41s
C++ / build (pull_request) Successful in 2m35s
Rust / build (pull_request) Successful in 1m49s
Rust / clippy (pull_request) Successful in 59s
Python / buildcheck (pull_request) Successful in 2m19s
C++ / clang-tidy (pull_request) Successful in 6m2s
2026-08-16 11:20:59 +02:00
zach 052e3a7800 Merge branch 'main' into feat/fullscreen-reveal-bar
C++ / fmt (pull_request) Successful in 9s
JS/TS / fmt (pull_request) Successful in 14s
JS/TS / lint (pull_request) Successful in 16s
Python / fmt (pull_request) Successful in 25s
Python / lint (pull_request) Successful in 26s
Python / test (pull_request) Successful in 52s
Python / typecheck (pull_request) Successful in 1m6s
Rust / fmt (pull_request) Successful in 33s
Rust / build (pull_request) Successful in 1m30s
Python / buildcheck (pull_request) Successful in 2m17s
C++ / build (pull_request) Successful in 3m49s
Rust / clippy (pull_request) Successful in 1m11s
C++ / clang-tidy (pull_request) Successful in 5m7s
2026-08-15 19:53:59 +02:00
zach 439a14d29e Initial commit implementing reveal on hover in fullscreen
C++ / fmt (pull_request) Successful in 5s
JS/TS / fmt (pull_request) Successful in 20s
JS/TS / lint (pull_request) Successful in 26s
Python / fmt (pull_request) Successful in 34s
Python / lint (pull_request) Successful in 32s
Python / test (pull_request) Successful in 59s
Python / typecheck (pull_request) Failing after 1m2s
C++ / build (pull_request) Successful in 1m50s
Rust / fmt (pull_request) Successful in 46s
Rust / build (pull_request) Successful in 1m40s
Python / buildcheck (pull_request) Successful in 2m27s
Rust / clippy (pull_request) Successful in 2m5s
C++ / clang-tidy (pull_request) Successful in 5m56s
2026-08-12 01:35:23 +02:00
18 changed files with 112 additions and 146 deletions
+4 -4
View File
@@ -126,7 +126,7 @@ MouseArea {
CustomRect { CustomRect {
id: item id: item
readonly property bool active: modelData === root?.active readonly property bool active: modelData === root.active
required property int index required property int index
required property MenuItem modelData required property MenuItem modelData
@@ -163,19 +163,19 @@ MouseArea {
MaterialIcon { MaterialIcon {
Layout.alignment: Qt.AlignVCenter Layout.alignment: Qt.AlignVCenter
color: item.active ? Colors.palette.m3onTertiaryContainer : Colors.palette.m3onSurfaceVariant color: item.active ? Colors.palette.m3onTertiaryContainer : Colors.palette.m3onSurfaceVariant
text: item.modelData?.icon ?? "" text: item.modelData.icon
} }
CustomText { CustomText {
Layout.alignment: Qt.AlignVCenter Layout.alignment: Qt.AlignVCenter
Layout.fillWidth: true Layout.fillWidth: true
color: item.active ? Colors.palette.m3onTertiaryContainer : Colors.palette.m3onSurface color: item.active ? Colors.palette.m3onTertiaryContainer : Colors.palette.m3onSurface
text: item.modelData?.text ?? "" text: item.modelData.text
} }
Loader { Loader {
Layout.alignment: Qt.AlignVCenter Layout.alignment: Qt.AlignVCenter
active: item.modelData?.trailingIcon.length > 0 active: item.modelData.trailingIcon.length > 0
asynchronous: true asynchronous: true
visible: active visible: active
+4
View File
@@ -1,6 +1,7 @@
pragma ComponentBehavior: Bound pragma ComponentBehavior: Bound
import Quickshell import Quickshell
import Quickshell.Wayland
import QtQuick import QtQuick
import ZShell.Config import ZShell.Config
import qs.Components import qs.Components
@@ -15,6 +16,9 @@ Scope {
ExclusionZone { ExclusionZone {
id: top id: top
WlrLayershell.layer: WlrLayer.Overlay
anchors.left: true
anchors.right: true
anchors.top: true anchors.top: true
hasBar: root.geometry.barOnTop hasBar: root.geometry.barOnTop
} }
+19 -1
View File
@@ -162,6 +162,19 @@ Item {
} }
} }
Timer {
id: unhideTimer
interval: Config.bar.revealDelay
repeat: false
running: false
onTriggered: {
if (hoverHandler.hovered)
root.bar.isHovered = true;
}
}
HoverHandler { HoverHandler {
id: hoverHandler id: hoverHandler
@@ -178,7 +191,7 @@ Item {
root.popouts.hasCurrent = false; root.popouts.hasCurrent = false;
} }
if (Config.bar.autoHide) if (Config.bar.autoHide || root.bar.fullscreen)
root.bar.isHovered = false; root.bar.isHovered = false;
} }
} }
@@ -200,6 +213,9 @@ Item {
if (!root.visibilities.bar && Config.bar.autoHide && root.geometry.barContains(x, y, true)) if (!root.visibilities.bar && Config.bar.autoHide && root.geometry.barContains(x, y, true))
root.bar.isHovered = true; root.bar.isHovered = true;
if (root.bar.fullscreen && !root.bar.isHovered)
unhideTimer.start();
if (root.panels.sidebar.offsetScale === 1) { if (root.panels.sidebar.offsetScale === 1) {
const showOsd = root.inRightPanel(root.panels.osdWrapper, x, y); const showOsd = root.inRightPanel(root.panels.osdWrapper, x, y);
@@ -302,6 +318,8 @@ Item {
root.visibilities.sidebar = false; root.visibilities.sidebar = false;
root.panels.popouts.hasCurrent = false; root.panels.popouts.hasCurrent = false;
root.visibilities.launcher = false; root.visibilities.launcher = false;
} else {
Config.save();
} }
} }
+8 -2
View File
@@ -51,7 +51,7 @@ CustomWindow {
readonly property HyprlandMonitor monitor: Hypr.monitorFor(screen) readonly property HyprlandMonitor monitor: Hypr.monitorFor(screen)
property var root: Quickshell.shellDir property var root: Quickshell.shellDir
readonly property real sdfBorderOffset: 2 * fsTransitionProg readonly property real sdfBorderOffset: 2 * fsTransitionProg
readonly property real shadowOpacity: 0.7 * (1 - fsTransitionProg) readonly property real shadowOpacity: 0.7 * (1 - (bar.isHovered ? 0 : fsTransitionProg))
property color surfaceColor: Colors.tPalette.m3surface property color surfaceColor: Colors.tPalette.m3surface
WlrLayershell.exclusionMode: ExclusionMode.Ignore WlrLayershell.exclusionMode: ExclusionMode.Ignore
@@ -59,7 +59,7 @@ CustomWindow {
WlrLayershell.layer: (fsTransitionProg > 0 && Config.general.showOverFullscreen) || (hasSpecialWorkspace && hasFullscreenOnNormalWs) ? WlrLayer.Overlay : WlrLayer.Top WlrLayershell.layer: (fsTransitionProg > 0 && Config.general.showOverFullscreen) || (hasSpecialWorkspace && hasFullscreenOnNormalWs) ? WlrLayer.Overlay : WlrLayer.Top
color: "transparent" color: "transparent"
contentItem.focus: true contentItem.focus: true
mask: visibilities.isDrawing ? null : (hasFullscreen ? emptyRegion : regions) mask: visibilities.isDrawing ? null : (hasFullscreen && !bar.isHovered ? emptyRegion : regions)
name: "Bar" name: "Bar"
Behavior on fsTransitionProg { Behavior on fsTransitionProg {
@@ -118,6 +118,12 @@ CustomWindow {
x: root.width - width x: root.width - width
y: panels.osdWrapper.y + bar.implicitHeight y: panels.osdWrapper.y + bar.implicitHeight
} }
Region {
height: geometry.horizontal ? 1 : root.screen.height
width: geometry.horizontal ? root.screen.width : 1
y: geometry.position === "bottom" ? root.screen.height - 1 : 0
}
} }
Regions { Regions {
+1
View File
@@ -73,6 +73,7 @@ Singleton {
Config.dock.pinnedApps = pinnedApps; Config.dock.pinnedApps = pinnedApps;
root.unpinnedOrder = visibleUnpinned.concat(root.unpinnedOrder.map(normalizeId).filter(id => !pinnedApps.includes(id) && !visibleUnpinned.includes(id))); root.unpinnedOrder = visibleUnpinned.concat(root.unpinnedOrder.map(normalizeId).filter(id => !pinnedApps.includes(id) && !visibleUnpinned.includes(id)));
Config.saveNoToast();
} }
function isPinned(appId) { function isPinned(appId) {
+10 -9
View File
@@ -12,6 +12,7 @@ GridLayout {
required property bool fullscreen required property bool fullscreen
required property bool horizontal required property bool horizontal
required property bool isHovered
required property Wrapper popouts required property Wrapper popouts
required property ClipWrapper popoutsWrapper required property ClipWrapper popoutsWrapper
required property ShellScreen screen required property ShellScreen screen
@@ -92,7 +93,7 @@ GridLayout {
delegate: EntryWrapper { delegate: EntryWrapper {
HyprsunsetWidget { HyprsunsetWidget {
horizontal: root.horizontal horizontal: root.horizontal
visible: !root.fullscreen visible: !root.fullscreen || root.isHovered
} }
} }
} }
@@ -113,7 +114,7 @@ GridLayout {
Workspaces { Workspaces {
horizontal: root.horizontal horizontal: root.horizontal
screen: root.screen screen: root.screen
visible: !root.fullscreen visible: !root.fullscreen || root.isHovered
} }
} }
} }
@@ -126,7 +127,7 @@ GridLayout {
horizontal: root.horizontal horizontal: root.horizontal
loader: root loader: root
popouts: root.popouts popouts: root.popouts
visible: !root.fullscreen visible: !root.fullscreen || root.isHovered
} }
} }
} }
@@ -148,7 +149,7 @@ GridLayout {
Resources { Resources {
horizontal: root.horizontal horizontal: root.horizontal
visibilities: root.visibilities visibilities: root.visibilities
visible: !root.fullscreen visible: !root.fullscreen || root.isHovered
} }
} }
} }
@@ -159,7 +160,7 @@ GridLayout {
delegate: EntryWrapper { delegate: EntryWrapper {
UpdatesWidget { UpdatesWidget {
horizontal: root.horizontal horizontal: root.horizontal
visible: !root.fullscreen visible: !root.fullscreen || root.isHovered
} }
} }
} }
@@ -172,7 +173,7 @@ GridLayout {
horizontal: root.horizontal horizontal: root.horizontal
popouts: root.popouts popouts: root.popouts
visibilities: root.visibilities visibilities: root.visibilities
visible: !root.fullscreen visible: !root.fullscreen || root.isHovered
} }
} }
} }
@@ -186,7 +187,7 @@ GridLayout {
loader: root loader: root
popouts: root.popouts popouts: root.popouts
visibilities: root.visibilities visibilities: root.visibilities
visible: !root.fullscreen visible: !root.fullscreen || root.isHovered
} }
} }
} }
@@ -198,7 +199,7 @@ GridLayout {
WindowTitle { WindowTitle {
bar: root bar: root
horizontal: root.horizontal horizontal: root.horizontal
visible: !root.fullscreen visible: !root.fullscreen || root.isHovered
} }
} }
} }
@@ -218,7 +219,7 @@ GridLayout {
delegate: EntryWrapper { delegate: EntryWrapper {
MediaWidget { MediaWidget {
horizontal: root.horizontal horizontal: root.horizontal
visible: !root.fullscreen visible: !root.fullscreen || root.isHovered
} }
} }
} }
+3 -1
View File
@@ -21,7 +21,7 @@ Item {
required property ClipWrapper popoutsWrapper required property ClipWrapper popoutsWrapper
required property string position required property string position
required property ShellScreen screen required property ShellScreen screen
readonly property bool shouldBeVisible: !fullscreen && (!Config.bar.autoHide || visibilities.bar || isHovered) readonly property bool shouldBeVisible: (!fullscreen && (!Config.bar.autoHide || visibilities.bar)) || isHovered
readonly property int vPadding: 6 readonly property int vPadding: 6
required property PersistentProperties visibilities required property PersistentProperties visibilities
@@ -79,7 +79,9 @@ Item {
sourceComponent: Bar { sourceComponent: Bar {
fullscreen: root.fullscreen fullscreen: root.fullscreen
height: root.contentHeight
horizontal: root.horizontal horizontal: root.horizontal
isHovered: root.isHovered
popouts: root.popouts popouts: root.popouts
popoutsWrapper: root.popoutsWrapper popoutsWrapper: root.popoutsWrapper
screen: root.screen screen: root.screen
@@ -82,6 +82,7 @@ Searcher {
list.visibilities.launcher = false; list.visibilities.launcher = false;
Quickshell.execDetached(["zshell-cli", "scheme", "generate", "--scheme", variant]); Quickshell.execDetached(["zshell-cli", "scheme", "generate", "--scheme", variant]);
Config.colors.schemeType = variant; Config.colors.schemeType = variant;
Config.save();
} }
} }
} }
+22 -1
View File
@@ -35,7 +35,6 @@ PageBase {
SelectRow { SelectRow {
active: Config.bar.position === "top" ? menuItems[0] : Config.bar.position === "left" ? menuItems[1] : menuItems[2] active: Config.bar.position === "top" ? menuItems[0] : Config.bar.position === "left" ? menuItems[1] : menuItems[2]
last: true
settingAnchor: "bar-position" settingAnchor: "bar-position"
subtext: qsTr("Change which edge the bar appears on") subtext: qsTr("Change which edge the bar appears on")
text: qsTr("Position") text: qsTr("Position")
@@ -61,6 +60,28 @@ PageBase {
onSelected: item => Config.bar.position = item.value onSelected: item => Config.bar.position = item.value
} }
ToggleRow {
checked: Config.bar.fullscreenReveal
settingAnchor: "bar-fullscreen-reveal"
subtext: qsTr("Hover top edge to show bar in fullscreen")
text: qsTr("Reveal on edge")
onToggled: Config.bar.fullscreenReveal = checked
}
SpinRow {
from: 0
last: true
settingAnchor: "bar-reveal-delay"
stepSize: 100
subtext: qsTr("The delay before bar is revealed when cursor is at edge")
text: qsTr("Reveal delay")
to: 2000
value: Config.bar.revealDelay
onMoved: v => Config.bar.revealDelay = v
}
// Components // Components
SectionHeader { SectionHeader {
text: qsTr("Components") text: qsTr("Components")
+4 -1
View File
@@ -70,7 +70,10 @@ PageBase {
} }
] ]
onSelected: item => Config.screenshot.mode = item.value onSelected: item => {
Config.screenshot.mode = item.value;
Config.save();
}
} }
SectionHeader { SectionHeader {
+2
View File
@@ -104,6 +104,7 @@ PageBase {
onApplySettings: (start, end) => { onApplySettings: (start, end) => {
Config.general.color.scheduleDarkStart = start; Config.general.color.scheduleDarkStart = start;
Config.general.color.scheduleDarkEnd = end; Config.general.color.scheduleDarkEnd = end;
Config.save();
ModeScheduler.checkStartup(); ModeScheduler.checkStartup();
PopupManager.requestClose(); PopupManager.requestClose();
} }
@@ -145,6 +146,7 @@ PageBase {
onApplySettings: (start, end) => { onApplySettings: (start, end) => {
Config.general.color.scheduleHyprsunsetStart = start; Config.general.color.scheduleHyprsunsetStart = start;
Config.general.color.scheduleHyprsunsetEnd = end; Config.general.color.scheduleHyprsunsetEnd = end;
Config.save();
Hyprsunset.checkStartup(); Hyprsunset.checkStartup();
PopupManager.requestClose(); PopupManager.requestClose();
} }
+19 -29
View File
@@ -95,31 +95,15 @@ QString Config::filePath() const {
void Config::loadSync() { void Config::loadSync() {
m_loading = true; m_loading = true;
QFile f(filePath()); QFile f(filePath());
QJsonObject before;
bool existed = false;
if (f.open(QIODevice::ReadOnly)) { if (f.open(QIODevice::ReadOnly)) {
const auto doc = QJsonDocument::fromJson(f.readAll()); const auto doc = QJsonDocument::fromJson(f.readAll());
if (doc.isObject()) { if (doc.isObject()) loadFromJson(QJsonValue(doc.object()));
before = doc.object();
existed = true;
} else {
qInfo() << "Config: existing config at" << filePath()
<< "is empty or not a valid JSON object - using defaults";
}
} else { } else {
qInfo() << "Config: no existing config at" << filePath() qInfo() << "Config: no existing config at" << filePath()
<< "- using defaults"; << "- using defaults";
} }
loadFromJson(QJsonValue(before));
m_loading = false; m_loading = false;
const auto after = toJson().toObject();
if (!existed || after != before) saveNow();
} }
void Config::updateWatch() { void Config::updateWatch() {
@@ -164,21 +148,27 @@ void Config::loadAsync() {
if (f.open(QIODevice::ReadOnly)) { if (f.open(QIODevice::ReadOnly)) {
const auto doc = QJsonDocument::fromJson(f.readAll()); const auto doc = QJsonDocument::fromJson(f.readAll());
const bool valid = doc.isObject();
const QJsonObject before = valid ? doc.object() : QJsonObject();
QMetaObject::invokeMethod( if (doc.isObject()) {
this, QMetaObject::invokeMethod(
[this, valid, before]() { this,
loadFromJson(QJsonValue(before)); [this, doc]() {
m_loading = false; loadFromJson(QJsonValue(doc.object()));
m_loading = false;
const auto after = toJson().toObject(); if (m_reloadPending) m_reloadTimer.start();
if (!valid || after != before) saveNow(); },
Qt::QueuedConnection);
} else {
QMetaObject::invokeMethod(
this,
[this]() {
m_loading = false;
if (m_reloadPending) m_reloadTimer.start(); if (m_reloadPending) m_reloadTimer.start();
}, },
Qt::QueuedConnection); Qt::QueuedConnection);
}
} else { } else {
qInfo() << "Config: failed to reload from" << filePath() qInfo() << "Config: failed to reload from" << filePath()
<< "- using in-memory values"; << "- using in-memory values";
+5 -14
View File
@@ -79,14 +79,13 @@ void ConfigList::loadFromJson(const QJsonValue& json) {
if (!json.isArray()) { if (!json.isArray()) {
qCWarning( qCWarning(
lcConfig, lcConfig,
"Option '%s' must be a list, resetting to default", "Option '%s' must be a list, ignoring",
qUtf8Printable(propertyPath())); qUtf8Printable(propertyPath()));
m_rejectedJson = json;
resetToDefaults();
materializeDefaults();
return; return;
} }
m_rejectedJson = QJsonValue::Undefined;
populate(json.toArray()); populate(json.toArray());
m_loaded = true; m_loaded = true;
} }
@@ -94,11 +93,12 @@ void ConfigList::loadFromJson(const QJsonValue& json) {
QJsonValue ConfigList::toJson() const { QJsonValue ConfigList::toJson() const {
if (m_loaded) return elementsToJson(); if (m_loaded) return elementsToJson();
return QJsonValue::Undefined; return m_rejectedJson;
} }
void ConfigList::clearLoadedKeys() { void ConfigList::clearLoadedKeys() {
m_loaded = false; m_loaded = false;
m_rejectedJson = QJsonValue::Undefined;
} }
QStringList ConfigList::unknownKeys() const { QStringList ConfigList::unknownKeys() const {
@@ -113,15 +113,6 @@ QStringList ConfigList::unknownKeys() const {
return keys; return keys;
} }
void ConfigList::materializeDefaults() {
for (auto* const item : m_items)
item->materializeDefaults();
if (m_global) return;
m_loaded = true;
}
void ConfigList::resyncFromGlobal() { void ConfigList::resyncFromGlobal() {
syncValuesFromGlobal(); syncValuesFromGlobal();
} }
+5 -3
View File
@@ -33,7 +33,6 @@ class ConfigList : public ConfigNode {
[[nodiscard]] QJsonValue toJson() const override; [[nodiscard]] QJsonValue toJson() const override;
void clearLoadedKeys() override; void clearLoadedKeys() override;
[[nodiscard]] QStringList unknownKeys() const override; [[nodiscard]] QStringList unknownKeys() const override;
void materializeDefaults() override;
void resyncFromGlobal() override; void resyncFromGlobal() override;
signals: signals:
@@ -72,6 +71,7 @@ class ConfigList : public ConfigNode {
QJsonArray m_defaults; QJsonArray m_defaults;
QList<ConfigObject*> m_items; QList<ConfigObject*> m_items;
bool m_loaded = false; bool m_loaded = false;
QJsonValue m_rejectedJson = QJsonValue::Undefined;
}; };
} // namespace ZShell::config } // namespace ZShell::config
@@ -103,6 +103,7 @@ class ConfigList : public ConfigNode {
} \ } \
}; };
#define CONFIG_LIST(Type, name, ...) \ #define CONFIG_LIST(Type, name, ...) \
Q_PROPERTY(ZShell::config::Type* name READ name CONSTANT) \ Q_PROPERTY(ZShell::config::Type* name READ name CONSTANT) \
\ \
@@ -114,8 +115,6 @@ class ConfigList : public ConfigNode {
private: \ private: \
Type* m_##name = new Type(this __VA_OPT__(, __VA_ARGS__)); Type* m_##name = new Type(this __VA_OPT__(, __VA_ARGS__));
#define LIST_ENTRY(id, enabled) \
vmap({{"id", QString::fromUtf8(#id)}, {"enabled", enabled}})
namespace ZShell::config { namespace ZShell::config {
@@ -137,3 +136,6 @@ class ListEntry : public ConfigObject {
CONFIG_LIST_TYPE(ListEntry, EntryList) CONFIG_LIST_TYPE(ListEntry, EntryList)
} // namespace ZShell::config } // namespace ZShell::config
#define LIST_ENTRY(id, enabled) \
vmap({{"id", QString::fromUtf8(#id)}, {"enabled", enabled}})
-2
View File
@@ -26,8 +26,6 @@ class ConfigNode : public QObject {
[[nodiscard]] virtual QStringList unknownKeys() const = 0; [[nodiscard]] virtual QStringList unknownKeys() const = 0;
[[nodiscard]] virtual QList<ConfigNode*> childNodes() const; [[nodiscard]] virtual QList<ConfigNode*> childNodes() const;
virtual void materializeDefaults() = 0;
void syncFromGlobal(ConfigNode* global); void syncFromGlobal(ConfigNode* global);
virtual void resyncFromGlobal() = 0; virtual void resyncFromGlobal() = 0;
+4 -78
View File
@@ -7,51 +7,6 @@
namespace ZShell::config { namespace ZShell::config {
namespace {
bool isStringArray(const QJsonArray& arr) {
for (const auto& v : arr) {
if (!v.isString()) return false;
}
return true;
}
bool jsonValueMatchesType(const QJsonValue& val, QMetaType type) {
switch (val.type()) {
case QJsonValue::Bool:
return type.id() == QMetaType::Bool;
case QJsonValue::Double:
switch (type.id()) {
case QMetaType::Int:
case QMetaType::UInt:
case QMetaType::LongLong:
case QMetaType::ULongLong:
case QMetaType::Double:
case QMetaType::Float:
return true;
default:
return false;
}
case QJsonValue::String:
return type.id() == QMetaType::QString;
case QJsonValue::Array:
if (type.id() == QMetaType::QStringList)
return isStringArray(val.toArray());
return type.id() == QMetaType::QVariantList;
case QJsonValue::Object:
case QJsonValue::Null:
case QJsonValue::Undefined:
default:
return false;
}
}
} // namespace
ConfigObject::ConfigObject(QObject* parent) : ConfigNode(parent) {} ConfigObject::ConfigObject(QObject* parent) : ConfigNode(parent) {}
void ConfigObject::loadFromJson(const QJsonValue& json) { void ConfigObject::loadFromJson(const QJsonValue& json) {
@@ -59,7 +14,6 @@ void ConfigObject::loadFromJson(const QJsonValue& json) {
const auto* meta = metaObject(); const auto* meta = metaObject();
QSet<QString> known; QSet<QString> known;
QSet<QString> invalid;
for (int i = basePropertyOffset(); i < meta->propertyCount(); ++i) { for (int i = basePropertyOffset(); i < meta->propertyCount(); ++i) {
auto prop = meta->property(i); auto prop = meta->property(i);
@@ -80,15 +34,6 @@ void ConfigObject::loadFromJson(const QJsonValue& json) {
if (!prop.isWritable()) continue; if (!prop.isWritable()) continue;
if (!jsonValueMatchesType(jsonVal, prop.metaType())) {
qWarning() << "Config: type mismatch for" << key << "in"
<< meta->className() << "- expected"
<< prop.metaType().name() << "got value" << jsonVal
<< "- resetting to default";
invalid.insert(key);
continue;
}
if (prop.metaType().id() == QMetaType::QStringList) { if (prop.metaType().id() == QMetaType::QStringList) {
QStringList list; QStringList list;
const auto jsonArr = jsonVal.toArray(); const auto jsonArr = jsonVal.toArray();
@@ -111,12 +56,10 @@ void ConfigObject::loadFromJson(const QJsonValue& json) {
m_extras = {}; m_extras = {};
for (auto it = obj.begin(); it != obj.end(); ++it) { for (auto it = obj.begin(); it != obj.end(); ++it) {
if (!known.contains(it.key()) || invalid.contains(it.key())) { if (!known.contains(it.key())) {
m_extras.insert(it.key(), it.value()); m_extras.insert(it.key(), it.value());
} }
} }
materializeDefaults();
} }
QJsonValue ConfigObject::toJson() const { QJsonValue ConfigObject::toJson() const {
@@ -161,6 +104,9 @@ QJsonValue ConfigObject::toJson() const {
obj.insert(key, QJsonValue::fromVariant(value)); obj.insert(key, QJsonValue::fromVariant(value));
} }
for (auto it = m_extras.begin(); it != m_extras.end(); ++it)
obj.insert(it.key(), it.value());
if (obj.isEmpty()) return QJsonValue::Undefined; if (obj.isEmpty()) return QJsonValue::Undefined;
return obj; return obj;
@@ -213,26 +159,6 @@ QList<ConfigNode*> ConfigObject::childNodes() const {
return nodes; return nodes;
} }
void ConfigObject::materializeDefaults() {
const auto* meta = metaObject();
for (int i = basePropertyOffset(); i < meta->propertyCount(); ++i) {
const auto prop = meta->property(i);
const auto key = QString::fromUtf8(prop.name());
if (auto* const node = prop.read(this).value<ConfigNode*>()) {
node->materializeDefaults();
continue;
}
if (!prop.isWritable()) continue;
if (m_global) continue;
m_loadedKeys.insert(key);
}
}
void ConfigObject::syncValuesFromGlobal() { void ConfigObject::syncValuesFromGlobal() {
const auto* meta = metaObject(); const auto* meta = metaObject();
-1
View File
@@ -62,7 +62,6 @@ class ConfigObject : public ConfigNode {
void clearLoadedKeys() override; void clearLoadedKeys() override;
[[nodiscard]] QStringList unknownKeys() const override; [[nodiscard]] QStringList unknownKeys() const override;
[[nodiscard]] QList<ConfigNode*> childNodes() const override; [[nodiscard]] QList<ConfigNode*> childNodes() const override;
void materializeDefaults() override;
void resyncFromGlobal() override; void resyncFromGlobal() override;
[[nodiscard]] virtual QStringList identityKeys() const; [[nodiscard]] virtual QStringList identityKeys() const;
+1
View File
@@ -113,6 +113,7 @@ Singleton {
function setMode(mode: string): void { function setMode(mode: string): void {
Quickshell.execDetached(["zshell-cli", "scheme", "generate", "--mode", mode]); Quickshell.execDetached(["zshell-cli", "scheme", "generate", "--mode", mode]);
Config.general.color.mode = mode; Config.general.color.mode = mode;
Config.save();
} }
function swapRG(c: color): color { function swapRG(c: color): color {