diff options
Diffstat (limited to 'accounts/gkleen@sif')
| -rw-r--r-- | accounts/gkleen@sif/default.nix | 1 | ||||
| -rw-r--r-- | accounts/gkleen@sif/shell/default.nix | 20 | ||||
| -rw-r--r-- | accounts/gkleen@sif/shell/quickshell-plugins/CMakeLists.txt | 116 | ||||
| -rw-r--r-- | accounts/gkleen@sif/shell/quickshell-plugins/Chrono.cpp | 88 | ||||
| -rw-r--r-- | accounts/gkleen@sif/shell/quickshell-plugins/Chrono.hpp | 57 | ||||
| -rw-r--r-- | accounts/gkleen@sif/shell/quickshell-plugins/customplugin.h | 7 | ||||
| -rw-r--r-- | accounts/gkleen@sif/shell/quickshell-plugins/default.nix | 20 | ||||
| -rw-r--r-- | accounts/gkleen@sif/shell/quickshell/Bar.qml | 81 | ||||
| -rw-r--r-- | accounts/gkleen@sif/shell/quickshell/shell.qml | 13 |
9 files changed, 403 insertions, 0 deletions
diff --git a/accounts/gkleen@sif/default.nix b/accounts/gkleen@sif/default.nix index 64434bb8..d509eeef 100644 --- a/accounts/gkleen@sif/default.nix +++ b/accounts/gkleen@sif/default.nix | |||
| @@ -71,6 +71,7 @@ in { | |||
| 71 | imports = [ | 71 | imports = [ |
| 72 | ./libvirt | 72 | ./libvirt |
| 73 | ./niri | 73 | ./niri |
| 74 | ./shell | ||
| 74 | ./synadm | 75 | ./synadm |
| 75 | flakeInputs.nix-index-database.homeModules.nix-index | 76 | flakeInputs.nix-index-database.homeModules.nix-index |
| 76 | flakeInputs.impermanence.nixosModules.home-manager.impermanence | 77 | flakeInputs.impermanence.nixosModules.home-manager.impermanence |
diff --git a/accounts/gkleen@sif/shell/default.nix b/accounts/gkleen@sif/shell/default.nix new file mode 100644 index 00000000..405ae4b6 --- /dev/null +++ b/accounts/gkleen@sif/shell/default.nix | |||
| @@ -0,0 +1,20 @@ | |||
| 1 | { config, pkgs, lib, ... }: | ||
| 2 | |||
| 3 | { | ||
| 4 | config = { | ||
| 5 | programs.quickshell = { | ||
| 6 | enable = true; | ||
| 7 | config = { | ||
| 8 | src = ./quickshell; | ||
| 9 | replacements = { | ||
| 10 | coreutils = toString pkgs.coreutils; | ||
| 11 | }; | ||
| 12 | }; | ||
| 13 | }; | ||
| 14 | systemd.user.services.quickshell = { | ||
| 15 | Service = { | ||
| 16 | Environment = "QML_IMPORT_PATH=${pkgs.qt6Packages.callPackage ./quickshell-plugins {}}/${pkgs.qt6.qtbase.qtQmlPrefix}"; | ||
| 17 | }; | ||
| 18 | }; | ||
| 19 | }; | ||
| 20 | } | ||
diff --git a/accounts/gkleen@sif/shell/quickshell-plugins/CMakeLists.txt b/accounts/gkleen@sif/shell/quickshell-plugins/CMakeLists.txt new file mode 100644 index 00000000..aa363c4c --- /dev/null +++ b/accounts/gkleen@sif/shell/quickshell-plugins/CMakeLists.txt | |||
| @@ -0,0 +1,116 @@ | |||
| 1 | set(INSTALL_QMLDIR "" CACHE STRING "QML install dir") | ||
| 2 | set(INSTALL_QML_PREFIX "" CACHE STRING "QML install prefix") | ||
| 3 | |||
| 4 | # There doesn't seem to be a standard cross-distro qml install path. | ||
| 5 | if ("${INSTALL_QMLDIR}" STREQUAL "" AND "${INSTALL_QML_PREFIX}" STREQUAL "") | ||
| 6 | message(WARNING "Neither INSTALL_QMLDIR nor INSTALL_QML_PREFIX is set. QML modules will not be installed.") | ||
| 7 | else() | ||
| 8 | if ("${INSTALL_QMLDIR}" STREQUAL "") | ||
| 9 | set(QML_FULL_INSTALLDIR "${CMAKE_INSTALL_PREFIX}/${INSTALL_QML_PREFIX}") | ||
| 10 | else() | ||
| 11 | set(QML_FULL_INSTALLDIR "${INSTALL_QMLDIR}") | ||
| 12 | endif() | ||
| 13 | |||
| 14 | message(STATUS "QML install dir: ${QML_FULL_INSTALLDIR}") | ||
| 15 | endif() | ||
| 16 | |||
| 17 | # Install a given target as a QML module. This is mostly pulled from ECM, as there does not seem | ||
| 18 | # to be an official way to do it. | ||
| 19 | # see https://github.com/KDE/extra-cmake-modules/blob/fe0f606bf7f222e36f7560fd7a2c33ef993e23bb/modules/ECMQmlModule6.cmake#L160 | ||
| 20 | function(install_qml_module arg_TARGET) | ||
| 21 | if (NOT DEFINED QML_FULL_INSTALLDIR) | ||
| 22 | return() | ||
| 23 | endif() | ||
| 24 | |||
| 25 | qt_query_qml_module(${arg_TARGET} | ||
| 26 | URI module_uri | ||
| 27 | VERSION module_version | ||
| 28 | PLUGIN_TARGET module_plugin_target | ||
| 29 | TARGET_PATH module_target_path | ||
| 30 | QMLDIR module_qmldir | ||
| 31 | TYPEINFO module_typeinfo | ||
| 32 | QML_FILES module_qml_files | ||
| 33 | RESOURCES module_resources | ||
| 34 | ) | ||
| 35 | |||
| 36 | set(module_dir "${QML_FULL_INSTALLDIR}/${module_target_path}") | ||
| 37 | |||
| 38 | if (NOT TARGET "${module_plugin_target}") | ||
| 39 | message(FATAL_ERROR "install_qml_modules called for a target without a plugin") | ||
| 40 | endif() | ||
| 41 | |||
| 42 | get_target_property(target_type "${arg_TARGET}" TYPE) | ||
| 43 | if (NOT "${target_type}" STREQUAL "STATIC_LIBRARY") | ||
| 44 | install( | ||
| 45 | TARGETS "${arg_TARGET}" | ||
| 46 | LIBRARY DESTINATION "${module_dir}" | ||
| 47 | RUNTIME DESTINATION "${module_dir}" | ||
| 48 | ) | ||
| 49 | |||
| 50 | install( | ||
| 51 | TARGETS "${module_plugin_target}" | ||
| 52 | LIBRARY DESTINATION "${module_dir}" | ||
| 53 | RUNTIME DESTINATION "${module_dir}" | ||
| 54 | ) | ||
| 55 | endif() | ||
| 56 | |||
| 57 | install(FILES "${module_qmldir}" DESTINATION "${module_dir}") | ||
| 58 | install(FILES "${module_typeinfo}" DESTINATION "${module_dir}") | ||
| 59 | |||
| 60 | # Install QML files | ||
| 61 | list(LENGTH module_qml_files num_files) | ||
| 62 | if (NOT "${module_qml_files}" MATCHES "NOTFOUND" AND ${num_files} GREATER 0) | ||
| 63 | qt_query_qml_module(${arg_TARGET} QML_FILES_DEPLOY_PATHS qml_files_deploy_paths) | ||
| 64 | |||
| 65 | math(EXPR last_index "${num_files} - 1") | ||
| 66 | foreach(i RANGE 0 ${last_index}) | ||
| 67 | list(GET module_qml_files ${i} src_file) | ||
| 68 | list(GET qml_files_deploy_paths ${i} deploy_path) | ||
| 69 | get_filename_component(dst_name "${deploy_path}" NAME) | ||
| 70 | get_filename_component(dest_dir "${deploy_path}" DIRECTORY) | ||
| 71 | install(FILES "${src_file}" DESTINATION "${module_dir}/${dest_dir}" RENAME "${dst_name}") | ||
| 72 | endforeach() | ||
| 73 | endif() | ||
| 74 | |||
| 75 | # Install resources | ||
| 76 | list(LENGTH module_resources num_files) | ||
| 77 | if (NOT "${module_resources}" MATCHES "NOTFOUND" AND ${num_files} GREATER 0) | ||
| 78 | qt_query_qml_module(${arg_TARGET} RESOURCES_DEPLOY_PATHS resources_deploy_paths) | ||
| 79 | |||
| 80 | math(EXPR last_index "${num_files} - 1") | ||
| 81 | foreach(i RANGE 0 ${last_index}) | ||
| 82 | list(GET module_resources ${i} src_file) | ||
| 83 | list(GET resources_deploy_paths ${i} deploy_path) | ||
| 84 | get_filename_component(dst_name "${deploy_path}" NAME) | ||
| 85 | get_filename_component(dest_dir "${deploy_path}" DIRECTORY) | ||
| 86 | install(FILES "${src_file}" DESTINATION "${module_dir}/${dest_dir}" RENAME "${dst_name}") | ||
| 87 | endforeach() | ||
| 88 | endif() | ||
| 89 | endfunction() | ||
| 90 | |||
| 91 | |||
| 92 | cmake_minimum_required(VERSION 3.20) | ||
| 93 | project(custom LANGUAGES CXX) | ||
| 94 | |||
| 95 | find_package(Qt6 REQUIRED COMPONENTS Core Qml) | ||
| 96 | |||
| 97 | qt_standard_project_setup(REQUIRES 6.6) | ||
| 98 | |||
| 99 | qt6_policy(SET QTP0001 NEW) | ||
| 100 | qt6_add_qml_module(customplugin | ||
| 101 | URI "Custom" | ||
| 102 | PLUGIN_TARGET customplugin | ||
| 103 | ) | ||
| 104 | |||
| 105 | target_sources(customplugin PRIVATE | ||
| 106 | Chrono.cpp Chrono.hpp | ||
| 107 | ) | ||
| 108 | |||
| 109 | target_compile_features(customplugin PUBLIC cxx_std_26) | ||
| 110 | |||
| 111 | target_link_libraries(customplugin PRIVATE | ||
| 112 | Qt6::Core | ||
| 113 | Qt6::Qml | ||
| 114 | ) | ||
| 115 | |||
| 116 | install_qml_module(customplugin) | ||
diff --git a/accounts/gkleen@sif/shell/quickshell-plugins/Chrono.cpp b/accounts/gkleen@sif/shell/quickshell-plugins/Chrono.cpp new file mode 100644 index 00000000..929b7be6 --- /dev/null +++ b/accounts/gkleen@sif/shell/quickshell-plugins/Chrono.cpp | |||
| @@ -0,0 +1,88 @@ | |||
| 1 | #include "Chrono.hpp" | ||
| 2 | |||
| 3 | #include <format> | ||
| 4 | #include <iostream> | ||
| 5 | #include <cmath> | ||
| 6 | |||
| 7 | Chrono::Chrono(QObject* parent): QObject(parent) { | ||
| 8 | QObject::connect(&this->timer, &QTimer::timeout, this, &Chrono::onTimeout); | ||
| 9 | this->update(); | ||
| 10 | } | ||
| 11 | |||
| 12 | bool Chrono::enabled() const { return this->mEnabled; } | ||
| 13 | |||
| 14 | void Chrono::setEnabled(bool enabled) { | ||
| 15 | if (enabled == this->mEnabled) return; | ||
| 16 | this->mEnabled = enabled; | ||
| 17 | emit this->enabledChanged(); | ||
| 18 | this->update(); | ||
| 19 | } | ||
| 20 | |||
| 21 | Chrono::Precision Chrono::precision() const { return this->mPrecision; } | ||
| 22 | |||
| 23 | void Chrono::setPrecision(Chrono::Precision precision) { | ||
| 24 | if (precision == this->mPrecision) return; | ||
| 25 | this->mPrecision = precision; | ||
| 26 | emit this->precisionChanged(); | ||
| 27 | this->update(); | ||
| 28 | } | ||
| 29 | |||
| 30 | void Chrono::onTimeout() { | ||
| 31 | this->setTime(this->targetTime); | ||
| 32 | this->schedule(this->targetTime); | ||
| 33 | } | ||
| 34 | |||
| 35 | void Chrono::update() { | ||
| 36 | if (this->mEnabled) { | ||
| 37 | this->setTime(std::chrono::time_point<std::chrono::system_clock>()); | ||
| 38 | this->schedule(std::chrono::time_point<std::chrono::system_clock>()); | ||
| 39 | } else { | ||
| 40 | this->timer.stop(); | ||
| 41 | } | ||
| 42 | } | ||
| 43 | |||
| 44 | void Chrono::setTime(const std::chrono::time_point<std::chrono::system_clock>& targetTime) { | ||
| 45 | auto currentTime = std::chrono::system_clock::now(); | ||
| 46 | auto offset = std::chrono::duration_cast<std::chrono::milliseconds>(targetTime - currentTime); | ||
| 47 | this->currentTime = abs(offset.count()) < 500 ? targetTime : currentTime; | ||
| 48 | |||
| 49 | switch (this->mPrecision) { | ||
| 50 | case Chrono::Hours: this->currentTime = std::chrono::time_point_cast<std::chrono::hours>(this->currentTime); | ||
| 51 | case Chrono::Minutes: this->currentTime = std::chrono::time_point_cast<std::chrono::minutes>(this->currentTime); | ||
| 52 | case Chrono::Seconds: this->currentTime = std::chrono::time_point_cast<std::chrono::seconds>(this->currentTime); | ||
| 53 | } | ||
| 54 | |||
| 55 | emit this->dateChanged(); | ||
| 56 | } | ||
| 57 | |||
| 58 | void Chrono::schedule(const std::chrono::time_point<std::chrono::system_clock>& targetTime) { | ||
| 59 | auto currentTime = std::chrono::system_clock::now(); | ||
| 60 | auto offset = std::chrono::duration_cast<std::chrono::milliseconds>(targetTime - currentTime); | ||
| 61 | auto nextTime = abs(offset.count()) < 500 ? targetTime : currentTime; | ||
| 62 | |||
| 63 | { | ||
| 64 | using namespace std::chrono_literals; | ||
| 65 | |||
| 66 | switch (this->mPrecision) { | ||
| 67 | case Chrono::Hours: nextTime = std::chrono::time_point_cast<std::chrono::hours>(nextTime) + 1h; | ||
| 68 | case Chrono::Minutes: nextTime = std::chrono::time_point_cast<std::chrono::minutes>(nextTime) + 1min; | ||
| 69 | case Chrono::Seconds: nextTime = std::chrono::time_point_cast<std::chrono::seconds>(nextTime) + 1s; | ||
| 70 | } | ||
| 71 | } | ||
| 72 | |||
| 73 | this->targetTime = nextTime; | ||
| 74 | auto delay = std::chrono::duration_cast<std::chrono::milliseconds>(nextTime - currentTime); | ||
| 75 | this->timer.start(delay); | ||
| 76 | } | ||
| 77 | |||
| 78 | QString Chrono::format() const { return this->mFormat; } | ||
| 79 | void Chrono::setFormat(QString format) { | ||
| 80 | if (format == this->mFormat) return; | ||
| 81 | this->mFormat = format; | ||
| 82 | emit this->formatChanged(); | ||
| 83 | this->update(); | ||
| 84 | } | ||
| 85 | |||
| 86 | QString Chrono::date() const { | ||
| 87 | return QString::fromStdString(std::format(std::runtime_format(this->mFormat.toStdString()), std::chrono::zoned_time(std::chrono::current_zone(), std::chrono::time_point_cast<std::chrono::seconds>(this->currentTime)))); | ||
| 88 | } | ||
diff --git a/accounts/gkleen@sif/shell/quickshell-plugins/Chrono.hpp b/accounts/gkleen@sif/shell/quickshell-plugins/Chrono.hpp new file mode 100644 index 00000000..788fa88e --- /dev/null +++ b/accounts/gkleen@sif/shell/quickshell-plugins/Chrono.hpp | |||
| @@ -0,0 +1,57 @@ | |||
| 1 | #pragma once | ||
| 2 | |||
| 3 | #include <QObject> | ||
| 4 | #include <QTimer> | ||
| 5 | |||
| 6 | #include <qqmlintegration.h> | ||
| 7 | #include <chrono> | ||
| 8 | |||
| 9 | class Chrono : public QObject { | ||
| 10 | Q_OBJECT; | ||
| 11 | Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged); | ||
| 12 | Q_PROPERTY(Chrono::Precision precision READ precision WRITE setPrecision NOTIFY precisionChanged); | ||
| 13 | Q_PROPERTY(QString format READ format WRITE setFormat NOTIFY formatChanged); | ||
| 14 | Q_PROPERTY(QString date READ date NOTIFY dateChanged); | ||
| 15 | QML_ELEMENT; | ||
| 16 | |||
| 17 | public: | ||
| 18 | enum Precision : quint8 { | ||
| 19 | Hours = 1, | ||
| 20 | Minutes = 2, | ||
| 21 | Seconds = 3, | ||
| 22 | }; | ||
| 23 | Q_ENUM(Precision); | ||
| 24 | |||
| 25 | explicit Chrono(QObject* parent = nullptr); | ||
| 26 | |||
| 27 | bool enabled() const; | ||
| 28 | void setEnabled(bool enabled); | ||
| 29 | |||
| 30 | Chrono::Precision precision() const; | ||
| 31 | void setPrecision(Chrono::Precision precision); | ||
| 32 | |||
| 33 | QString format() const; | ||
| 34 | void setFormat (QString format); | ||
| 35 | |||
| 36 | QString date() const; | ||
| 37 | |||
| 38 | signals: | ||
| 39 | void enabledChanged(); | ||
| 40 | void precisionChanged(); | ||
| 41 | void formatChanged(); | ||
| 42 | void dateChanged(); | ||
| 43 | |||
| 44 | private slots: | ||
| 45 | void onTimeout(); | ||
| 46 | |||
| 47 | private: | ||
| 48 | bool mEnabled = true; | ||
| 49 | Chrono::Precision mPrecision = Chrono::Seconds; | ||
| 50 | QString mFormat = "{:%c}"; | ||
| 51 | QTimer timer; | ||
| 52 | std::chrono::time_point<std::chrono::system_clock> currentTime, targetTime; | ||
| 53 | |||
| 54 | void update(); | ||
| 55 | void setTime(const std::chrono::time_point<std::chrono::system_clock>& targetTime); | ||
| 56 | void schedule(const std::chrono::time_point<std::chrono::system_clock>& targetTime); | ||
| 57 | }; | ||
diff --git a/accounts/gkleen@sif/shell/quickshell-plugins/customplugin.h b/accounts/gkleen@sif/shell/quickshell-plugins/customplugin.h new file mode 100644 index 00000000..e66ba9e3 --- /dev/null +++ b/accounts/gkleen@sif/shell/quickshell-plugins/customplugin.h | |||
| @@ -0,0 +1,7 @@ | |||
| 1 | #include <QQmlEngineExtensionPlugin> | ||
| 2 | |||
| 3 | class CustomPlugin : public QQmlEngineExtensionPlugin | ||
| 4 | { | ||
| 5 | Q_OBJECT | ||
| 6 | Q_PLUGIN_METADATA(IID QQmlEngineExtensionInterface_iid) | ||
| 7 | }; | ||
diff --git a/accounts/gkleen@sif/shell/quickshell-plugins/default.nix b/accounts/gkleen@sif/shell/quickshell-plugins/default.nix new file mode 100644 index 00000000..fafea90e --- /dev/null +++ b/accounts/gkleen@sif/shell/quickshell-plugins/default.nix | |||
| @@ -0,0 +1,20 @@ | |||
| 1 | { lib | ||
| 2 | , stdenv | ||
| 3 | , cmake | ||
| 4 | , qt6 | ||
| 5 | , fmt | ||
| 6 | }: | ||
| 7 | stdenv.mkDerivation rec { | ||
| 8 | name = "quickshell-custom"; | ||
| 9 | |||
| 10 | src = ./.; | ||
| 11 | nativeBuildInputs = [ cmake qt6.wrapQtAppsHook ]; | ||
| 12 | buildInputs = [ | ||
| 13 | qt6.qtbase | ||
| 14 | qt6.qtdeclarative | ||
| 15 | ]; | ||
| 16 | |||
| 17 | cmakeFlags = [ | ||
| 18 | (lib.cmakeFeature "INSTALL_QML_PREFIX" qt6.qtbase.qtQmlPrefix) | ||
| 19 | ]; | ||
| 20 | } | ||
diff --git a/accounts/gkleen@sif/shell/quickshell/Bar.qml b/accounts/gkleen@sif/shell/quickshell/Bar.qml new file mode 100644 index 00000000..b7235a61 --- /dev/null +++ b/accounts/gkleen@sif/shell/quickshell/Bar.qml | |||
| @@ -0,0 +1,81 @@ | |||
| 1 | import Quickshell | ||
| 2 | import Quickshell.Io | ||
| 3 | import Custom as Custom | ||
| 4 | import QtQuick | ||
| 5 | |||
| 6 | |||
| 7 | PanelWindow { | ||
| 8 | property var modelData | ||
| 9 | |||
| 10 | anchors { | ||
| 11 | bottom: true | ||
| 12 | left: true | ||
| 13 | right: true | ||
| 14 | } | ||
| 15 | margins { | ||
| 16 | left: 26 + 8 | ||
| 17 | right: 26 + 8 | ||
| 18 | } | ||
| 19 | |||
| 20 | screen: modelData | ||
| 21 | implicitHeight: 21 | ||
| 22 | color: Qt.rgba(0, 0, 0, 0.66) | ||
| 23 | |||
| 24 | Row { | ||
| 25 | id: left | ||
| 26 | |||
| 27 | height: parent.height | ||
| 28 | anchors.left: parent.left | ||
| 29 | anchors.leftMargin: 8 | ||
| 30 | anchors.verticalCenter: parent.verticalCenter | ||
| 31 | spacing: 5 | ||
| 32 | |||
| 33 | Text { | ||
| 34 | color: "white" | ||
| 35 | anchors.verticalCenter: parent.verticalCenter | ||
| 36 | text: "left" | ||
| 37 | } | ||
| 38 | } | ||
| 39 | |||
| 40 | Row { | ||
| 41 | id: center | ||
| 42 | |||
| 43 | height: parent.height | ||
| 44 | anchors.centerIn: parent | ||
| 45 | spacing: 5 | ||
| 46 | |||
| 47 | Text { | ||
| 48 | color: "white" | ||
| 49 | anchors.verticalCenter: parent.verticalCenter | ||
| 50 | text: "center" | ||
| 51 | } | ||
| 52 | } | ||
| 53 | |||
| 54 | Row { | ||
| 55 | id: right | ||
| 56 | |||
| 57 | height: parent.height | ||
| 58 | anchors.right: parent.right | ||
| 59 | anchors.rightMargin: 8 | ||
| 60 | anchors.verticalCenter: parent.verticalCenter | ||
| 61 | spacing: 5 | ||
| 62 | |||
| 63 | Text { | ||
| 64 | id: clock | ||
| 65 | color: "white" | ||
| 66 | |||
| 67 | anchors.verticalCenter: parent.verticalCenter | ||
| 68 | |||
| 69 | Custom.Chrono { | ||
| 70 | id: chrono | ||
| 71 | format: "W{0:%V-%u} {0:%F} {0:%H:%M:%S%Ez}" | ||
| 72 | } | ||
| 73 | |||
| 74 | text: chrono.date | ||
| 75 | |||
| 76 | font.pointSize: 10 | ||
| 77 | font.family: "Fira Sans" | ||
| 78 | font.features: { "tnum": 1 } | ||
| 79 | } | ||
| 80 | } | ||
| 81 | } \ No newline at end of file | ||
diff --git a/accounts/gkleen@sif/shell/quickshell/shell.qml b/accounts/gkleen@sif/shell/quickshell/shell.qml new file mode 100644 index 00000000..35fe5344 --- /dev/null +++ b/accounts/gkleen@sif/shell/quickshell/shell.qml | |||
| @@ -0,0 +1,13 @@ | |||
| 1 | import Quickshell | ||
| 2 | |||
| 3 | ShellRoot { | ||
| 4 | settings.watchFiles: false | ||
| 5 | |||
| 6 | Variants { | ||
| 7 | model: Quickshell.screens | ||
| 8 | |||
| 9 | delegate: Bar { | ||
| 10 | modelData: item | ||
| 11 | } | ||
| 12 | } | ||
| 13 | } | ||
