From 3c359ce25f5596402e3470b38af8aafb85235d7c Mon Sep 17 00:00:00 2001 From: zach Date: Wed, 30 Sep 2026 18:38:07 +0200 Subject: [PATCH] fix: re-add lost changes --- CMakeLists.txt | 40 +++---- Plugins/CMakeLists.txt | 23 ++++ Plugins/ZShell/Blobs/CMakeLists.txt | 26 ++--- Plugins/ZShell/Config/CMakeLists.txt | 10 +- Plugins/ZShell/Config/rootnodes.hpp | 2 - Plugins/ZShell/Models/CMakeLists.txt | 12 +- Plugins/ZShell/zutils.cpp | 157 ++++++++++++++++++++++++++- Plugins/ZShell/zutils.hpp | 21 +++- Plugins/cmake/pch.cmake | 14 +++ Plugins/cmake/sensorslib.cmake | 10 ++ Plugins/include/util/metaenum.hpp | 31 ++++++ 11 files changed, 292 insertions(+), 54 deletions(-) create mode 100644 Plugins/cmake/pch.cmake create mode 100644 Plugins/cmake/sensorslib.cmake create mode 100644 Plugins/include/util/metaenum.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 95c3714..fc9f50a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,22 +26,36 @@ if(NOT DEFINED VERSION) endif() endif() +if(NOT DEFINED GIT_REVISION) + execute_process(COMMAND git rev-parse HEAD + WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" + OUTPUT_VARIABLE GIT_REVISION + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + + if("${GIT_REVISION}" STREQUAL "") + message(FATAL_ERROR "GIT_REVISION is not set and failed to get from git") + endif() +endif() + set(VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}") project(ZShell VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}) message(STATUS "ZShell version: ${VERSION}") +include(GNUInstallDirs) + set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib") set(CMAKE_EXPORT_COMPILE_COMMANDS ON) -set(ENABLE_MODULES "plugin;shell;m3shapes" CACHE STRING "Modules to build/install") +set(ENABLE_MODULES "plugin;shell;cli;m3shapes" CACHE STRING "Modules to build/install") -set(INSTALL_LIBDIR "usr/lib/ZShell" CACHE STRING "Library install dir") -set(INSTALL_QMLDIR "usr/lib/qt6/qml" CACHE STRING "QML install dir") -set(INSTALL_QSCONFDIR "etc/xdg/quickshell/zshell" CACHE STRING "Quickshell config install dir") -set(INSTALL_GREETERCONFDIR "etc/xdg/quickshell/zshell-greeter" CACHE STRING "Quickshell greeter install dir") +set(INSTALL_LIBDIR "${CMAKE_INSTALL_LIBDIR}/ZShell" CACHE STRING "Library install dir") +set(INSTALL_QMLDIR "${CMAKE_INSTALL_LIBDIR}/qt6/qml" CACHE STRING "QML install dir") +set(INSTALL_QSCONFDIR "${CMAKE_INSTALL_SYSCONFDIR}/xdg/quickshell/zshell" CACHE STRING "Quickshell config install dir") +set(INSTALL_GREETERCONFDIR "${CMAKE_INSTALL_SYSCONFDIR}/xdg/quickshell/zshell-greeter" CACHE STRING "Quickshell greeter install dir") set(CMAKE_INSTALL_MESSAGE NEVER) @@ -54,21 +68,7 @@ add_compile_options( ) -if("shell" IN_LIST ENABLE_MODULES) - # Build settings index - find_package(Python3 COMPONENTS Interpreter REQUIRED) - set(SETTINGS_INDEX_JSON "${CMAKE_BINARY_DIR}/settings-index.json") - execute_process( - COMMAND ${Python3_EXECUTABLE} - "${CMAKE_SOURCE_DIR}/scripts/build-settings-index.py" - "${CMAKE_SOURCE_DIR}/Modules/Settings" - "${SETTINGS_INDEX_JSON}" - RESULT_VARIABLE SETTINGS_INDEX_RESULT - ) - if(NOT SETTINGS_INDEX_RESULT EQUAL 0) - message(FATAL_ERROR "Failed to build settings search index") - endif() - +if("cli" IN_LIST ENABLE_MODULES) # Nuitka compilation set(ZSHELL_CLI_BUILD_DIR "${CMAKE_BINARY_DIR}/zshell-cli") set(ZSHELL_CLI_DIST "${ZSHELL_CLI_BUILD_DIR}/zshell.dist") diff --git a/Plugins/CMakeLists.txt b/Plugins/CMakeLists.txt index 4a2ff2f..5c302ae 100644 --- a/Plugins/CMakeLists.txt +++ b/Plugins/CMakeLists.txt @@ -1 +1,24 @@ +find_package(Qt6 REQUIRED COMPONENTS ShaderTools Core Qml Gui Quick QuickPrivate Concurrent Sql Network DBus CanvasPainter) +find_package(PkgConfig REQUIRED) +pkg_check_modules(Qalculate IMPORTED_TARGET libqalculate REQUIRED) +pkg_check_modules(Pipewire IMPORTED_TARGET libpipewire-0.3 REQUIRED) +pkg_check_modules(Aubio IMPORTED_TARGET aubio REQUIRED) +pkg_check_modules(Cava IMPORTED_TARGET libcava QUIET) +pkg_check_modules(GLIB REQUIRED glib-2.0 gobject-2.0 gio-2.0) + +if(NOT Cava_FOUND) + pkg_check_modules(Cava IMPORTED_TARGET cava REQUIRED) +endif() + +include(cmake/sensorslib.cmake) + +set(QT_QML_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/qml") +qt_standard_project_setup(REQUIRES 6.9) + +include(cmake/pch.cmake) +include(cmake/qml-module.cmake) + +add_library(zshell-util INTERFACE) +target_include_directories(zshell-util INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/include") + add_subdirectory(ZShell) diff --git a/Plugins/ZShell/Blobs/CMakeLists.txt b/Plugins/ZShell/Blobs/CMakeLists.txt index 05ec0d9..a51b194 100644 --- a/Plugins/ZShell/Blobs/CMakeLists.txt +++ b/Plugins/ZShell/Blobs/CMakeLists.txt @@ -1,20 +1,20 @@ qml_module(ZShell-blobs URI ZShell.Blobs - SOURCES - blobgroup.cpp - blobshape.cpp - blobrect.cpp - blobinvertedrect.cpp - blobmaterial.cpp - LIBRARIES - Qt::Quick + SOURCES + blobgroup.cpp + blobshape.cpp + blobrect.cpp + blobinvertedrect.cpp + blobmaterial.cpp + LIBRARIES + Qt::Quick ) qt_add_shaders(ZShell-blobs "blob_shaders" - BATCHABLE OPTIMIZED NOHLSL NOMSL + BATCHABLE OPTIMIZED NOHLSL NOMSL GLSL "300es,330" - PREFIX "/" - FILES - shaders/blob.frag - shaders/blob.vert + PREFIX "/" + FILES + shaders/blob.frag + shaders/blob.vert ) diff --git a/Plugins/ZShell/Config/CMakeLists.txt b/Plugins/ZShell/Config/CMakeLists.txt index 350ab9a..d17da2a 100644 --- a/Plugins/ZShell/Config/CMakeLists.txt +++ b/Plugins/ZShell/Config/CMakeLists.txt @@ -1,13 +1,9 @@ qml_module(ZShell-config URI ZShell.Config INCLUDE_PREFIX config - DEPENDENCIES - ZShell.Settings SOURCES - confignode.hpp confignode.cpp - configobject.hpp configobject.cpp - configlist.hpp configlist.cpp - config.hpp config.cpp + rootnodes.hpp rootnodes.cpp + common.hpp common.cpp migration.hpp migration.cpp anim.hpp anim.cpp fontbuilder.hpp fontbuilder.cpp @@ -31,6 +27,8 @@ qml_module(ZShell-config services.hpp sidebar.hpp utilities.hpp + DEPENDENCIES + ZShell.Settings ) target_link_libraries(ZShell-config PUBLIC diff --git a/Plugins/ZShell/Config/rootnodes.hpp b/Plugins/ZShell/Config/rootnodes.hpp index 308e90a..bbbe3c5 100644 --- a/Plugins/ZShell/Config/rootnodes.hpp +++ b/Plugins/ZShell/Config/rootnodes.hpp @@ -16,7 +16,6 @@ #include "dock.hpp" #include "general.hpp" #include "launcher.hpp" -#include "llm.hpp" #include "lock.hpp" #include "notifs.hpp" #include "osd.hpp" @@ -43,7 +42,6 @@ class ConfigRoot : public settings::RootNode { CONFIG_SUBOBJECT(Dock, dock) CONFIG_SUBOBJECT(General, general) CONFIG_SUBOBJECT(Launcher, launcher) - CONFIG_SUBOBJECT(Llm, llm) CONFIG_SUBOBJECT(Lock, lock) CONFIG_SUBOBJECT(Notifs, notifs) CONFIG_SUBOBJECT(Osd, osd) diff --git a/Plugins/ZShell/Models/CMakeLists.txt b/Plugins/ZShell/Models/CMakeLists.txt index 785db17..9bac1a8 100644 --- a/Plugins/ZShell/Models/CMakeLists.txt +++ b/Plugins/ZShell/Models/CMakeLists.txt @@ -1,8 +1,8 @@ qml_module(ZShell-models - URI ZShell.Models - SOURCES - filesystemmodel.hpp filesystemmodel.cpp - LIBRARIES - Qt::Gui - Qt::Concurrent + URI ZShell.Models + SOURCES + filesystemmodel.hpp filesystemmodel.cpp + LIBRARIES + Qt::Gui + Qt::Concurrent ) diff --git a/Plugins/ZShell/zutils.cpp b/Plugins/ZShell/zutils.cpp index 4aef1fe..8a81a39 100644 --- a/Plugins/ZShell/zutils.cpp +++ b/Plugins/ZShell/zutils.cpp @@ -5,13 +5,17 @@ #include #include #include +#include #include #include #include #include +#include #include #include +#include "util/metaenum.hpp" + Q_LOGGING_CATEGORY(lcZUtils, "ZShell.cutils", QtInfoMsg) namespace ZShell { @@ -171,13 +175,112 @@ qreal ZUtils::clamp(qreal value, qreal min, qreal max) { return qBound(min, value, max); } -QString ZUtils::settingsIndex() { - QFile file(QStringLiteral(":/qt/qml/ZShell/settings-index.json")); - if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { - qCWarning(lcZUtils) << "Failed to open embedded settings index"; - return QString(); +QString ZUtils::enumToString( + QObject* target, const QString& property, const QVariant& value) { + if (!target) { + qCWarning(lcZUtils) << "enumToString: a target is required"; + return {}; } - return QString::fromUtf8(file.readAll()); + + const auto* meta = target->metaObject(); + const auto index = meta->indexOfProperty(property.toUtf8().constData()); + if (index < 0) { + qCWarning(lcZUtils) + << "enumToString:" << target << "has no property" << property; + return {}; + } + + const auto prop = meta->property(index); + const auto metaEnum = prop.isEnumType() + ? prop.enumerator() + : util::metaEnumFor(prop.metaType()); + if (!metaEnum.isValid() || metaEnum.is64Bit()) { + qCWarning(lcZUtils) << "enumToString: property" << property << "of" + << target << "is not a supported enum"; + return {}; + } + + const auto val = value.isValid() ? value : prop.read(target); + const auto* key = util::enumKeyFor(metaEnum, val); + if (!key) { + qCWarning( + lcZUtils, + "enumToString: no enumerator of %s::%s has the value %lld", + metaEnum.scope(), + metaEnum.name(), + val.toLongLong()); + return {}; + } + + return QString::fromUtf8(key); +} + +namespace { + +template +QQuickItem* findChildDfs(QQuickItem* root, Predicate&& match) { + const auto children = root->childItems(); + for (QQuickItem* const child : children) { + if (match(child)) { + return child; + } + if (QQuickItem* const found = findChildDfs(child, match)) { + return found; + } + } + return nullptr; +} + +template +void findChildrenDfs( + QQuickItem* root, Predicate&& match, QList& out) { + const auto children = root->childItems(); + for (QQuickItem* const child : children) { + if (match(child)) { + out.append(child); + } + findChildrenDfs(child, match, out); + } +} + +} // namespace + +QQuickItem* ZUtils::findChild(QQuickItem* root, const QString& name) { + if (!root) { + return nullptr; + } + + return findChildDfs(root, [&name](const QQuickItem* item) { + return item->objectName() == name; + }); +} + +QList ZUtils::findChildren(QQuickItem* root, const QString& name) { + QList children; + if (root) { + findChildrenDfs( + root, + [&name](const QQuickItem* item) { + return item->objectName() == name; + }, + children); + } + return children; +} + +QList ZUtils::findChildrenMatching( + QQuickItem* root, const QString& pattern) { + QList children; + if (root) { + const QRegularExpression re(pattern); + findChildrenDfs( + root, + [&re](const QQuickItem* item) { + return re.match(item->objectName()).hasMatch(); + }, + children); + } + return children; } #ifndef ZSHELL_VERSION @@ -192,4 +295,46 @@ QString ZUtils::qtVersion() const { return QStringLiteral(QT_VERSION_STR); } +QString ZUtils::gitRevision() { +#ifdef GIT_REVISION + return QStringLiteral(GIT_REVISION); +#else + return QString(); +#endif +} + +QString ZUtils::readTextFile(const QString& path) { + QFile file(path); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + return QString(); + } + return QString::fromUtf8(file.readAll()); +} + +bool ZUtils::writeTextFile(const QString& path, const QString& text) { + const QFileInfo info(path); + if (!QDir().mkpath(info.absolutePath())) { + qCWarning(lcZUtils) << "Failed to create directory for" << path; + return false; + } + QFile file(path); + if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { + qCWarning(lcZUtils) << "Failed to open" << path << "for writing"; + return false; + } + return file.write(text.toUtf8()) >= 0; +} + +QStringList ZUtils::listFiles(const QString& dir, const QString& suffix) { + QStringList out; + QDirIterator it(dir, QDirIterator::Subdirectories); + while (it.hasNext()) { + const QString path = it.next(); + if (it.fileInfo().isFile() && path.endsWith(suffix)) { + out.append(path); + } + } + return out; +} + } // namespace ZShell diff --git a/Plugins/ZShell/zutils.hpp b/Plugins/ZShell/zutils.hpp index 1e9b3f8..3900cc0 100644 --- a/Plugins/ZShell/zutils.hpp +++ b/Plugins/ZShell/zutils.hpp @@ -4,6 +4,8 @@ #include #include #include +#include +#include namespace ZShell { @@ -32,7 +34,24 @@ class ZUtils : public QObject { Q_INVOKABLE static qreal clamp(qreal value, qreal min, qreal max); - Q_INVOKABLE static QString settingsIndex(); + Q_INVOKABLE static QString enumToString( + QObject* target, + const QString& property, + const QVariant& value = QVariant()); + + Q_INVOKABLE static QString gitRevision(); + Q_INVOKABLE static QString readTextFile(const QString& path); + Q_INVOKABLE static bool writeTextFile( + const QString& path, const QString& text); + Q_INVOKABLE static QStringList listFiles( + const QString& dir, const QString& suffix); + + Q_INVOKABLE static QQuickItem* findChild( + QQuickItem* root, const QString& name); + Q_INVOKABLE static QList findChildren( + QQuickItem* root, const QString& name); + Q_INVOKABLE static QList findChildrenMatching( + QQuickItem* root, const QString& pattern); [[nodiscard]] QString version() const; [[nodiscard]] QString qtVersion() const; diff --git a/Plugins/cmake/pch.cmake b/Plugins/cmake/pch.cmake new file mode 100644 index 0000000..c5685fb --- /dev/null +++ b/Plugins/cmake/pch.cmake @@ -0,0 +1,14 @@ +add_library(zshell-pch INTERFACE) +target_precompile_headers(zshell-pch INTERFACE + + + + + + + + + + + +) diff --git a/Plugins/cmake/sensorslib.cmake b/Plugins/cmake/sensorslib.cmake new file mode 100644 index 0000000..b7333a2 --- /dev/null +++ b/Plugins/cmake/sensorslib.cmake @@ -0,0 +1,10 @@ +find_library(SENSORS_LIBRARY NAMES sensors REQUIRED) +find_path(SENSORS_INCLUDE_DIR NAMES sensors/sensors.h REQUIRED) +if(NOT TARGET Sensors::Sensors) + add_library(Sensors::Sensors UNKNOWN IMPORTED) + set_target_properties(Sensors::Sensors PROPERTIES + IMPORTED_LOCATION "${SENSORS_LIBRARY}" + INTERFACE_INCLUDE_DIRECTORIES "${SENSORS_INCLUDE_DIR}" + ) +endif() + diff --git a/Plugins/include/util/metaenum.hpp b/Plugins/include/util/metaenum.hpp new file mode 100644 index 0000000..25f6786 --- /dev/null +++ b/Plugins/include/util/metaenum.hpp @@ -0,0 +1,31 @@ +#pragma once + +#include +#include +#include + +namespace util { + +inline QMetaEnum metaEnumFor(const QMetaType& type) { + const auto* meta = type.metaObject(); + if (!meta) return {}; + + auto name = QByteArray(type.name()); + if (const auto scope = name.lastIndexOf("::"); scope >= 0) + name = name.mid(scope + 2); + + return meta->enumerator(meta->indexOfEnumerator(name.constData())); +} + +inline bool isSupportedEnum(const QMetaType& type) { + if (!type.flags().testFlag(QMetaType::IsEnumeration)) return false; + + const auto metaEnum = metaEnumFor(type); + return metaEnum.isValid() && !metaEnum.is64Bit(); +} + +inline const char* enumKeyFor(const QMetaEnum& metaEnum, const QVariant& value) { + return metaEnum.valueToKey(static_cast(value.toLongLong())); +} + +} // namespace util