service/tray: rework tray image providers

This commit is contained in:
outfoxxed 2024-04-29 22:28:09 -07:00
parent aa9f8cd001
commit 7cc1b54587
Signed by: outfoxxed
GPG key ID: 4C88A185FB89301E
10 changed files with 163 additions and 82 deletions

View file

@ -23,6 +23,7 @@ qt_add_library(quickshell-core STATIC
lazyloader.cpp lazyloader.cpp
easingcurve.cpp easingcurve.cpp
iconimageprovider.cpp iconimageprovider.cpp
imageprovider.cpp
transformwatcher.cpp transformwatcher.cpp
) )

View file

@ -16,6 +16,7 @@
#include <qtmetamacros.h> #include <qtmetamacros.h>
#include "iconimageprovider.hpp" #include "iconimageprovider.hpp"
#include "imageprovider.hpp"
#include "incubator.hpp" #include "incubator.hpp"
#include "plugin.hpp" #include "plugin.hpp"
#include "qsintercept.hpp" #include "qsintercept.hpp"
@ -35,6 +36,8 @@ EngineGeneration::EngineGeneration(QmlScanner scanner)
this->engine->setIncubationController(&this->delayedIncubationController); this->engine->setIncubationController(&this->delayedIncubationController);
this->engine->addImageProvider("icon", new IconImageProvider()); this->engine->addImageProvider("icon", new IconImageProvider());
this->engine->addImageProvider("qsimage", new QsImageProvider());
this->engine->addImageProvider("qspixmap", new QsPixmapProvider());
QuickshellPlugin::runConstructGeneration(*this); QuickshellPlugin::runConstructGeneration(*this);
} }

View file

@ -0,0 +1,83 @@
#include "imageprovider.hpp"
#include <qdebug.h>
#include <qimage.h>
#include <qlogging.h>
#include <qmap.h>
#include <qobject.h>
#include <qpixmap.h>
#include <qqmlengine.h>
static QMap<QString, QsImageHandle*> liveImages;
QsImageHandle::QsImageHandle(QQmlImageProviderBase::ImageType type, QObject* parent)
: QObject(parent)
, type(type) {
{
auto dbg = QDebug(&this->id);
dbg.nospace() << static_cast<void*>(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();
}
}

View file

@ -0,0 +1,39 @@
#pragma once
#include <qimage.h>
#include <qmap.h>
#include <qobject.h>
#include <qqmlengine.h>
#include <qquickimageprovider.h>
#include <qtclasshelpermacros.h>
#include <qtmetamacros.h>
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;
};

View file

@ -27,7 +27,6 @@ qt_add_dbus_interface(DBUS_INTERFACES
qt_add_library(quickshell-service-statusnotifier STATIC qt_add_library(quickshell-service-statusnotifier STATIC
qml.cpp qml.cpp
trayimageprovider.cpp
watcher.cpp watcher.cpp
host.cpp host.cpp
@ -36,8 +35,6 @@ qt_add_library(quickshell-service-statusnotifier STATIC
${DBUS_INTERFACES} ${DBUS_INTERFACES}
) )
add_library(quickshell-service-statusnotifier-init OBJECT init.cpp)
# dbus headers # dbus headers
target_include_directories(quickshell-service-statusnotifier PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) 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 PRIVATE ${QT_DEPS} quickshell-dbus)
target_link_libraries(quickshell-service-statusnotifier-init PRIVATE ${QT_DEPS}) target_link_libraries(quickshell PRIVATE quickshell-service-statusnotifierplugin)
target_link_libraries(quickshell PRIVATE quickshell-service-statusnotifierplugin quickshell-service-statusnotifier-init)
qs_pch(quickshell-service-statusnotifier) qs_pch(quickshell-service-statusnotifier)
qs_pch(quickshell-service-statusnotifierplugin) qs_pch(quickshell-service-statusnotifierplugin)
qs_pch(quickshell-service-statusnotifier-init)

View file

@ -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

View file

@ -11,12 +11,15 @@
#include <qobject.h> #include <qobject.h>
#include <qpainter.h> #include <qpainter.h>
#include <qpixmap.h> #include <qpixmap.h>
#include <qqmlengine.h>
#include <qrect.h> #include <qrect.h>
#include <qsize.h> #include <qsize.h>
#include <qstring.h> #include <qstring.h>
#include <qtmetamacros.h> #include <qtmetamacros.h>
#include <qtypes.h>
#include "../../core/iconimageprovider.hpp" #include "../../core/iconimageprovider.hpp"
#include "../../core/imageprovider.hpp"
#include "../../dbus/properties.hpp" #include "../../dbus/properties.hpp"
#include "dbus_item.h" #include "dbus_item.h"
#include "dbus_item_types.hpp" #include "dbus_item_types.hpp"
@ -94,7 +97,7 @@ QString StatusNotifierItem::iconId() const {
return IconImageProvider::requestString(name, this->iconThemePath.get()); 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 { QPixmap StatusNotifierItem::createPixmap(const QSize& size) const {
@ -230,4 +233,22 @@ void StatusNotifierItem::onGetAllFinished() {
emit this->ready(); 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 } // namespace qs::service::sni

View file

@ -9,6 +9,7 @@
#include <qtmetamacros.h> #include <qtmetamacros.h>
#include <qtypes.h> #include <qtypes.h>
#include "../../core/imageprovider.hpp"
#include "../../dbus/properties.hpp" #include "../../dbus/properties.hpp"
#include "dbus_item.h" #include "dbus_item.h"
#include "dbus_item_types.hpp" #include "dbus_item_types.hpp"
@ -17,6 +18,18 @@ Q_DECLARE_LOGGING_CATEGORY(logStatusNotifierItem);
namespace qs::service::sni { 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 { class StatusNotifierItem: public QObject {
Q_OBJECT; Q_OBJECT;
@ -62,6 +75,7 @@ private slots:
private: private:
DBusStatusNotifierItem* item = nullptr; DBusStatusNotifierItem* item = nullptr;
TrayImageHandle imageHandle {this};
bool mReady = false; bool mReady = false;
// bumped to inhibit caching // bumped to inhibit caching

View file

@ -1,44 +0,0 @@
#include "trayimageprovider.hpp"
#include <qlogging.h>
#include <qloggingcategory.h>
#include <qpixmap.h>
#include <qsize.h>
#include <qstring.h>
#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

View file

@ -1,16 +0,0 @@
#pragma once
#include <qpixmap.h>
#include <qquickimageprovider.h>
#include <qtmetamacros.h>
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