diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 31cf726..294e8f9 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -23,6 +23,7 @@ qt_add_library(quickshell-core STATIC lazyloader.cpp easingcurve.cpp iconimageprovider.cpp + imageprovider.cpp transformwatcher.cpp ) diff --git a/src/core/generation.cpp b/src/core/generation.cpp index 2431780..77e4a9c 100644 --- a/src/core/generation.cpp +++ b/src/core/generation.cpp @@ -16,6 +16,7 @@ #include #include "iconimageprovider.hpp" +#include "imageprovider.hpp" #include "incubator.hpp" #include "plugin.hpp" #include "qsintercept.hpp" @@ -35,6 +36,8 @@ EngineGeneration::EngineGeneration(QmlScanner scanner) this->engine->setIncubationController(&this->delayedIncubationController); this->engine->addImageProvider("icon", new IconImageProvider()); + this->engine->addImageProvider("qsimage", new QsImageProvider()); + this->engine->addImageProvider("qspixmap", new QsPixmapProvider()); QuickshellPlugin::runConstructGeneration(*this); } diff --git a/src/core/imageprovider.cpp b/src/core/imageprovider.cpp new file mode 100644 index 0000000..e33f6c1 --- /dev/null +++ b/src/core/imageprovider.cpp @@ -0,0 +1,83 @@ +#include "imageprovider.hpp" + +#include +#include +#include +#include +#include +#include +#include + +static QMap liveImages; + +QsImageHandle::QsImageHandle(QQmlImageProviderBase::ImageType type, QObject* parent) + : QObject(parent) + , type(type) { + { + auto dbg = QDebug(&this->id); + dbg.nospace() << static_cast(this); + } + + liveImages.insert(this->id, this); +} + +QsImageHandle::~QsImageHandle() { liveImages.remove(this->id); } + +QString QsImageHandle::url() const { + QString url = "image://"; + if (this->type == QQmlImageProviderBase::Image) url += "qsimage"; + else if (this->type == QQmlImageProviderBase::Pixmap) url += "qspixmap"; + url += "/" + this->id; + return url; +} + +QImage +QsImageHandle::requestImage(const QString& /*unused*/, QSize* /*unused*/, const QSize& /*unused*/) { + qWarning() << "Image handle" << this << "does not provide QImages"; + return QImage(); +} + +QPixmap QsImageHandle:: + requestPixmap(const QString& /*unused*/, QSize* /*unused*/, const QSize& /*unused*/) { + qWarning() << "Image handle" << this << "does not provide QPixmaps"; + return QPixmap(); +} + +void parseReq(const QString& req, QString& target, QString& param) { + auto splitIdx = req.indexOf('/'); + if (splitIdx != -1) { + target = req.sliced(0, splitIdx); + param = req.sliced(splitIdx + 1); + } else { + target = req; + } +} + +QImage QsImageProvider::requestImage(const QString& id, QSize* size, const QSize& requestedSize) { + QString target; + QString param; + parseReq(id, target, param); + + auto* handle = liveImages.value(target); + if (handle != nullptr) { + return handle->requestImage(param, size, requestedSize); + } else { + qWarning() << "Requested image from unknown handle" << id; + return QImage(); + } +} + +QPixmap +QsPixmapProvider::requestPixmap(const QString& id, QSize* size, const QSize& requestedSize) { + QString target; + QString param; + parseReq(id, target, param); + + auto* handle = liveImages.value(target); + if (handle != nullptr) { + return handle->requestPixmap(param, size, requestedSize); + } else { + qWarning() << "Requested image from unknown handle" << id; + return QPixmap(); + } +} diff --git a/src/core/imageprovider.hpp b/src/core/imageprovider.hpp new file mode 100644 index 0000000..5ea7843 --- /dev/null +++ b/src/core/imageprovider.hpp @@ -0,0 +1,39 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +class QsImageProvider: public QQuickImageProvider { +public: + explicit QsImageProvider(): QQuickImageProvider(QQuickImageProvider::Image) {} + QImage requestImage(const QString& id, QSize* size, const QSize& requestedSize) override; +}; + +class QsPixmapProvider: public QQuickImageProvider { +public: + explicit QsPixmapProvider(): QQuickImageProvider(QQuickImageProvider::Pixmap) {} + QPixmap requestPixmap(const QString& id, QSize* size, const QSize& requestedSize) override; +}; + +class QsImageHandle: public QObject { + Q_OBJECT; + +public: + explicit QsImageHandle(QQmlImageProviderBase::ImageType type, QObject* parent = nullptr); + ~QsImageHandle() override; + Q_DISABLE_COPY_MOVE(QsImageHandle); + + [[nodiscard]] QString url() const; + + virtual QImage requestImage(const QString& id, QSize* size, const QSize& requestedSize); + virtual QPixmap requestPixmap(const QString& id, QSize* size, const QSize& requestedSize); + +private: + QQmlImageProviderBase::ImageType type; + QString id; +}; diff --git a/src/services/status_notifier/CMakeLists.txt b/src/services/status_notifier/CMakeLists.txt index 689c347..c92b6a5 100644 --- a/src/services/status_notifier/CMakeLists.txt +++ b/src/services/status_notifier/CMakeLists.txt @@ -27,7 +27,6 @@ qt_add_dbus_interface(DBUS_INTERFACES qt_add_library(quickshell-service-statusnotifier STATIC qml.cpp - trayimageprovider.cpp watcher.cpp host.cpp @@ -36,8 +35,6 @@ qt_add_library(quickshell-service-statusnotifier STATIC ${DBUS_INTERFACES} ) -add_library(quickshell-service-statusnotifier-init OBJECT init.cpp) - # dbus headers target_include_directories(quickshell-service-statusnotifier PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) @@ -47,9 +44,7 @@ qt_add_qml_module(quickshell-service-statusnotifier ) target_link_libraries(quickshell-service-statusnotifier PRIVATE ${QT_DEPS} quickshell-dbus) -target_link_libraries(quickshell-service-statusnotifier-init PRIVATE ${QT_DEPS}) -target_link_libraries(quickshell PRIVATE quickshell-service-statusnotifierplugin quickshell-service-statusnotifier-init) +target_link_libraries(quickshell PRIVATE quickshell-service-statusnotifierplugin) qs_pch(quickshell-service-statusnotifier) qs_pch(quickshell-service-statusnotifierplugin) -qs_pch(quickshell-service-statusnotifier-init) diff --git a/src/services/status_notifier/init.cpp b/src/services/status_notifier/init.cpp deleted file mode 100644 index f96a27d..0000000 --- a/src/services/status_notifier/init.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include "../../core/generation.hpp" -#include "../../core/plugin.hpp" -#include "trayimageprovider.hpp" - -namespace { - -class SniPlugin: public QuickshellPlugin { - void constructGeneration(EngineGeneration& generation) override { - generation.engine->addImageProvider("service.sni", new qs::service::sni::TrayImageProvider()); - } -}; - -QS_REGISTER_PLUGIN(SniPlugin); - -} // namespace diff --git a/src/services/status_notifier/item.cpp b/src/services/status_notifier/item.cpp index a9e0bee..b3cceec 100644 --- a/src/services/status_notifier/item.cpp +++ b/src/services/status_notifier/item.cpp @@ -11,12 +11,15 @@ #include #include #include +#include #include #include #include #include +#include #include "../../core/iconimageprovider.hpp" +#include "../../core/imageprovider.hpp" #include "../../dbus/properties.hpp" #include "dbus_item.h" #include "dbus_item_types.hpp" @@ -94,7 +97,7 @@ QString StatusNotifierItem::iconId() const { return IconImageProvider::requestString(name, this->iconThemePath.get()); } - return QString("image://service.sni/") + this->watcherId + "/" + QString::number(this->iconIndex); + return this->imageHandle.url() + "/" + QString::number(this->iconIndex); } QPixmap StatusNotifierItem::createPixmap(const QSize& size) const { @@ -230,4 +233,22 @@ void StatusNotifierItem::onGetAllFinished() { emit this->ready(); } +TrayImageHandle::TrayImageHandle(StatusNotifierItem* item) + : QsImageHandle(QQmlImageProviderBase::Pixmap, item) + , item(item) {} + +QPixmap +TrayImageHandle::requestPixmap(const QString& /*unused*/, QSize* size, const QSize& requestedSize) { + auto targetSize = requestedSize.isValid() ? requestedSize : QSize(100, 100); + if (targetSize.width() == 0 || targetSize.height() == 0) targetSize = QSize(2, 2); + + auto pixmap = this->item->createPixmap(targetSize); + if (pixmap.isNull()) { + pixmap = IconImageProvider::missingPixmap(targetSize); + } + + if (size != nullptr) *size = pixmap.size(); + return pixmap; +} + } // namespace qs::service::sni diff --git a/src/services/status_notifier/item.hpp b/src/services/status_notifier/item.hpp index 24978a0..4e8c308 100644 --- a/src/services/status_notifier/item.hpp +++ b/src/services/status_notifier/item.hpp @@ -9,6 +9,7 @@ #include #include +#include "../../core/imageprovider.hpp" #include "../../dbus/properties.hpp" #include "dbus_item.h" #include "dbus_item_types.hpp" @@ -17,6 +18,18 @@ Q_DECLARE_LOGGING_CATEGORY(logStatusNotifierItem); namespace qs::service::sni { +class StatusNotifierItem; + +class TrayImageHandle: public QsImageHandle { +public: + explicit TrayImageHandle(StatusNotifierItem* item); + + QPixmap requestPixmap(const QString& id, QSize* size, const QSize& requestedSize) override; + +public: + StatusNotifierItem* item; +}; + class StatusNotifierItem: public QObject { Q_OBJECT; @@ -62,6 +75,7 @@ private slots: private: DBusStatusNotifierItem* item = nullptr; + TrayImageHandle imageHandle {this}; bool mReady = false; // bumped to inhibit caching diff --git a/src/services/status_notifier/trayimageprovider.cpp b/src/services/status_notifier/trayimageprovider.cpp deleted file mode 100644 index e75c638..0000000 --- a/src/services/status_notifier/trayimageprovider.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#include "trayimageprovider.hpp" - -#include -#include -#include -#include -#include - -#include "../../core/iconimageprovider.hpp" -#include "host.hpp" - -namespace qs::service::sni { - -QPixmap -TrayImageProvider::requestPixmap(const QString& id, QSize* size, const QSize& requestedSize) { - QPixmap pixmap; - - auto targetSize = requestedSize.isValid() ? requestedSize : QSize(100, 100); - if (targetSize.width() == 0 || targetSize.height() == 0) targetSize = QSize(2, 2); - - auto lastSplit = id.lastIndexOf('/'); - if (lastSplit == -1) { - qCWarning(logStatusNotifierHost) << "Invalid image request:" << id; - } else { - auto path = id.sliced(0, lastSplit); - - auto* item = StatusNotifierHost::instance()->itemByService(path); - - if (item == nullptr) { - qCWarning(logStatusNotifierHost) << "Image requested for nonexistant service" << path; - } else { - pixmap = item->createPixmap(targetSize); - } - } - - if (pixmap.isNull()) { - pixmap = IconImageProvider::missingPixmap(targetSize); - } - - if (size != nullptr) *size = pixmap.size(); - return pixmap; -} - -} // namespace qs::service::sni diff --git a/src/services/status_notifier/trayimageprovider.hpp b/src/services/status_notifier/trayimageprovider.hpp deleted file mode 100644 index a4b245b..0000000 --- a/src/services/status_notifier/trayimageprovider.hpp +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -#include -#include -#include - -namespace qs::service::sni { - -class TrayImageProvider: public QQuickImageProvider { -public: - explicit TrayImageProvider(): QQuickImageProvider(QQuickImageProvider::Pixmap) {} - - QPixmap requestPixmap(const QString& id, QSize* size, const QSize& requestedSize) override; -}; - -} // namespace qs::service::sni