diff --git a/src/services/status_notifier/dbus_item_types.cpp b/src/services/status_notifier/dbus_item_types.cpp index afb623ef..625864b8 100644 --- a/src/services/status_notifier/dbus_item_types.cpp +++ b/src/services/status_notifier/dbus_item_types.cpp @@ -1,7 +1,6 @@ #include "dbus_item_types.hpp" #include -#include #include #include #include @@ -10,6 +9,15 @@ #include #include +bool DBusSniIconPixmap::operator==(const DBusSniIconPixmap& other) const { + return this->width == other.width && this->height == other.height && this->data == other.data; +} + +bool DBusSniTooltip::operator==(const DBusSniTooltip& other) const { + return this->icon == other.icon && this->title == other.title + && this->description == other.description && this->iconPixmaps == other.iconPixmaps; +} + QImage DBusSniIconPixmap::createImage() const { // fix byte order if on a little endian machine if (QSysInfo::ByteOrder == QSysInfo::LittleEndian) { @@ -113,9 +121,3 @@ QDebug operator<<(QDebug debug, const DBusSniTooltip& tooltip) { return debug; } - -QDebug operator<<(QDebug debug, const QDBusObjectPath& path) { - debug.nospace() << "QDBusObjectPath(" << path.path() << ")"; - - return debug; -} diff --git a/src/services/status_notifier/dbus_item_types.hpp b/src/services/status_notifier/dbus_item_types.hpp index 13c1a94b..cef38f36 100644 --- a/src/services/status_notifier/dbus_item_types.hpp +++ b/src/services/status_notifier/dbus_item_types.hpp @@ -1,7 +1,6 @@ #pragma once #include -#include #include #include @@ -12,6 +11,8 @@ struct DBusSniIconPixmap { // valid only for the lifetime of the pixmap [[nodiscard]] QImage createImage() const; + + bool operator==(const DBusSniIconPixmap& other) const; }; using DBusSniIconPixmapList = QList; @@ -21,6 +22,8 @@ struct DBusSniTooltip { DBusSniIconPixmapList iconPixmaps; QString title; QString description; + + bool operator==(const DBusSniTooltip& other) const; }; const QDBusArgument& operator>>(const QDBusArgument& argument, DBusSniIconPixmap& pixmap); @@ -32,4 +35,3 @@ const QDBusArgument& operator<<(QDBusArgument& argument, const DBusSniTooltip& t QDebug operator<<(QDebug debug, const DBusSniIconPixmap& pixmap); QDebug operator<<(QDebug debug, const DBusSniTooltip& tooltip); -QDebug operator<<(QDebug debug, const QDBusObjectPath& path); diff --git a/src/services/status_notifier/item.cpp b/src/services/status_notifier/item.cpp index df898312..347edbbd 100644 --- a/src/services/status_notifier/item.cpp +++ b/src/services/status_notifier/item.cpp @@ -1,6 +1,6 @@ #include "item.hpp" -#include +#include #include #include #include @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -58,36 +59,71 @@ StatusNotifierItem::StatusNotifierItem(const QString& address, QObject* parent) } // clang-format off - QObject::connect(this->item, &DBusStatusNotifierItem::NewTitle, &this->pTitle, &AbstractDBusProperty::update); - QObject::connect(this->item, &DBusStatusNotifierItem::NewIcon, &this->pIconName, &AbstractDBusProperty::update); - QObject::connect(this->item, &DBusStatusNotifierItem::NewIcon, &this->pIconPixmaps, &AbstractDBusProperty::update); - QObject::connect(this->item, &DBusStatusNotifierItem::NewIcon, &this->pIconThemePath, &AbstractDBusProperty::update); - QObject::connect(this->item, &DBusStatusNotifierItem::NewOverlayIcon, &this->pOverlayIconName, &AbstractDBusProperty::update); - QObject::connect(this->item, &DBusStatusNotifierItem::NewOverlayIcon, &this->pOverlayIconPixmaps, &AbstractDBusProperty::update); - QObject::connect(this->item, &DBusStatusNotifierItem::NewOverlayIcon, &this->pIconThemePath, &AbstractDBusProperty::update); - QObject::connect(this->item, &DBusStatusNotifierItem::NewAttentionIcon, &this->pAttentionIconName, &AbstractDBusProperty::update); - QObject::connect(this->item, &DBusStatusNotifierItem::NewAttentionIcon, &this->pAttentionIconPixmaps, &AbstractDBusProperty::update); - QObject::connect(this->item, &DBusStatusNotifierItem::NewAttentionIcon, &this->pIconThemePath, &AbstractDBusProperty::update); - QObject::connect(this->item, &DBusStatusNotifierItem::NewToolTip, &this->pTooltip, &AbstractDBusProperty::update); + QObject::connect(this->item, &DBusStatusNotifierItem::NewTitle, this, [this]() { + this->pTitle.requestUpdate(); + }); - QObject::connect(&this->pIconThemePath, &AbstractDBusProperty::changed, this, &StatusNotifierItem::updateIcon); - QObject::connect(&this->pIconName, &AbstractDBusProperty::changed, this, &StatusNotifierItem::updateIcon); - QObject::connect(&this->pAttentionIconName, &AbstractDBusProperty::changed, this, &StatusNotifierItem::updateIcon); - QObject::connect(&this->pOverlayIconName, &AbstractDBusProperty::changed, this, &StatusNotifierItem::updateIcon); - QObject::connect(&this->pIconPixmaps, &AbstractDBusProperty::changed, this, &StatusNotifierItem::updateIcon); - QObject::connect(&this->pAttentionIconPixmaps, &AbstractDBusProperty::changed, this, &StatusNotifierItem::updateIcon); - QObject::connect(&this->pOverlayIconPixmaps, &AbstractDBusProperty::changed, this, &StatusNotifierItem::updateIcon); + QObject::connect(this->item, &DBusStatusNotifierItem::NewIcon, this, [this]() { + this->pIconName.requestUpdate(); + this->pIconPixmaps.requestUpdate(); + this->pIconThemePath.requestUpdate(); + }); + + QObject::connect(this->item, &DBusStatusNotifierItem::NewOverlayIcon, this, [this]() { + this->pOverlayIconName.requestUpdate(); + this->pOverlayIconPixmaps.requestUpdate(); + this->pIconThemePath.requestUpdate(); + }); + + QObject::connect(this->item, &DBusStatusNotifierItem::NewAttentionIcon, this, [this]() { + this->pAttentionIconName.requestUpdate(); + this->pAttentionIconPixmaps.requestUpdate(); + this->pIconThemePath.requestUpdate(); + }); + + QObject::connect(this->item, &DBusStatusNotifierItem::NewToolTip, this, [this]() { + this->pTooltip.requestUpdate(); + }); QObject::connect(&this->properties, &DBusPropertyGroup::getAllFinished, this, &StatusNotifierItem::onGetAllFinished); QObject::connect(&this->properties, &DBusPropertyGroup::getAllFailed, this, &StatusNotifierItem::onGetAllFailed); - QObject::connect(&this->pMenuPath, &AbstractDBusProperty::changed, this, &StatusNotifierItem::onMenuPathChanged); // clang-format on - QObject::connect(this->item, &DBusStatusNotifierItem::NewStatus, this, [this](QString value) { - qCDebug(logStatusNotifierItem) << "Received update for" << this->pStatus.toString() << value; - this->pStatus.set(std::move(value)); + this->bIcon.setBinding([this]() -> QString { + if (this->bStatus.value() == Status::NeedsAttention) { + auto name = this->bAttentionIconName.value(); + if (!name.isEmpty()) + return IconImageProvider::requestString(name, this->bIconThemePath.value()); + } else { + auto name = this->bIconName.value(); + auto overlayName = this->bOverlayIconName.value(); + if (!name.isEmpty() && overlayName.isEmpty()) + return IconImageProvider::requestString(name, this->bIconThemePath.value()); + } + + return this->imageHandle.url() % "/" % QString::number(this->pixmapIndex); }); + this->bHasMenu.setBinding([this]() { return !this->bMenuPath.value().path().isEmpty(); }); + + QObject::connect( + this->item, + &DBusStatusNotifierItem::NewStatus, + this, + [this](const QString& value) { + auto result = DBusDataTransform::fromWire(value); + + if (result.isValid()) { + this->bStatus = result.value; + qCDebug(logStatusNotifierItem) + << "Received status update for" << this->properties.toString() << result.value; + } else { + qCWarning(logStatusNotifierItem) + << "Received invalid status update for" << this->properties.toString() << value; + } + } + ); + this->properties.setInterface(this->item); this->properties.updateAllViaGetAll(); } @@ -95,22 +131,8 @@ StatusNotifierItem::StatusNotifierItem(const QString& address, QObject* parent) bool StatusNotifierItem::isValid() const { return this->item->isValid(); } bool StatusNotifierItem::isReady() const { return this->mReady; } -QString StatusNotifierItem::iconId() const { - if (this->pStatus.get() == "NeedsAttention") { - auto name = this->pAttentionIconName.get(); - if (!name.isEmpty()) return IconImageProvider::requestString(name, this->pIconThemePath.get()); - } else { - auto name = this->pIconName.get(); - auto overlayName = this->pOverlayIconName.get(); - if (!name.isEmpty() && overlayName.isEmpty()) - return IconImageProvider::requestString(name, this->pIconThemePath.get()); - } - - return this->imageHandle.url() + "/" + QString::number(this->iconIndex); -} - QPixmap StatusNotifierItem::createPixmap(const QSize& size) const { - auto needsAttention = this->pStatus.get() == "NeedsAttention"; + auto needsAttention = this->bStatus.value() == Status::NeedsAttention; auto closestPixmap = [](const QSize& size, const DBusSniIconPixmapList& pixmaps) { const DBusSniIconPixmap* ret = nullptr; @@ -135,11 +157,11 @@ QPixmap StatusNotifierItem::createPixmap(const QSize& size) const { QPixmap pixmap; if (needsAttention) { - if (!this->pAttentionIconName.get().isEmpty()) { - auto icon = QIcon::fromTheme(this->pAttentionIconName.get()); + if (!this->bAttentionIconName.value().isEmpty()) { + auto icon = QIcon::fromTheme(this->bAttentionIconName.value()); pixmap = icon.pixmap(size.width(), size.height()); } else { - const auto* icon = closestPixmap(size, this->pAttentionIconPixmaps.get()); + const auto* icon = closestPixmap(size, this->bAttentionIconPixmaps.value()); if (icon != nullptr) { const auto image = @@ -149,11 +171,11 @@ QPixmap StatusNotifierItem::createPixmap(const QSize& size) const { } } } else { - if (!this->pIconName.get().isEmpty()) { - auto icon = QIcon::fromTheme(this->pIconName.get()); + if (!this->bIconName.value().isEmpty()) { + auto icon = QIcon::fromTheme(this->bIconName.value()); pixmap = icon.pixmap(size.width(), size.height()); } else { - const auto* icon = closestPixmap(size, this->pIconPixmaps.get()); + const auto* icon = closestPixmap(size, this->bIconPixmaps.value()); if (icon != nullptr) { const auto image = @@ -164,11 +186,11 @@ QPixmap StatusNotifierItem::createPixmap(const QSize& size) const { } QPixmap overlay; - if (!this->pOverlayIconName.get().isEmpty()) { - auto icon = QIcon::fromTheme(this->pOverlayIconName.get()); + if (!this->bOverlayIconName.value().isEmpty()) { + auto icon = QIcon::fromTheme(this->bOverlayIconName.value()); overlay = icon.pixmap(pixmap.width(), pixmap.height()); } else { - const auto* icon = closestPixmap(pixmap.size(), this->pOverlayIconPixmaps.get()); + const auto* icon = closestPixmap(pixmap.size(), this->bOverlayIconPixmaps.value()); if (icon != nullptr) { const auto image = @@ -231,17 +253,14 @@ void StatusNotifierItem::scroll(qint32 delta, bool horizontal) const { this->item->Scroll(delta, horizontal ? "horizontal" : "vertical"); } -void StatusNotifierItem::updateIcon() { - this->iconIndex++; - emit this->iconChanged(); -} +void StatusNotifierItem::updatePixmapIndex() { this->pixmapIndex = this->pixmapIndex + 1; } DBusMenuHandle* StatusNotifierItem::menuHandle() { - return this->pMenuPath.get().path().isEmpty() ? nullptr : &this->mMenuHandle; + return this->bMenuPath.value().path().isEmpty() ? nullptr : &this->mMenuHandle; } void StatusNotifierItem::onMenuPathChanged() { - this->mMenuHandle.setAddress(this->item->service(), this->pMenuPath.get().path()); + this->mMenuHandle.setAddress(this->item->service(), this->bMenuPath.value().path()); } void StatusNotifierItem::onGetAllFinished() { @@ -282,41 +301,6 @@ TrayImageHandle::requestPixmap(const QString& /*unused*/, QSize* size, const QSi return pixmap; } -QString StatusNotifierItem::id() const { return this->pId.get(); } -QString StatusNotifierItem::title() const { return this->pTitle.get(); } - -Status::Enum StatusNotifierItem::status() const { - auto status = this->pStatus.get(); - - if (status == "Passive") return Status::Passive; - if (status == "Active") return Status::Active; - if (status == "NeedsAttention") return Status::NeedsAttention; - - qCWarning(logStatusNotifierItem) << "Nonconformant StatusNotifierItem status" << status - << "returned for" << this->properties.toString(); - - return Status::Passive; -} - -Category::Enum StatusNotifierItem::category() const { - auto category = this->pCategory.get(); - - if (category == "ApplicationStatus") return Category::ApplicationStatus; - if (category == "SystemServices") return Category::SystemServices; - if (category == "Hardware") return Category::Hardware; - - qCWarning(logStatusNotifierItem) << "Nonconformant StatusNotifierItem category" << category - << "returned for" << this->properties.toString(); - - return Category::ApplicationStatus; -} - -QString StatusNotifierItem::tooltipTitle() const { return this->pTooltip.get().title; } -QString StatusNotifierItem::tooltipDescription() const { return this->pTooltip.get().description; } - -bool StatusNotifierItem::hasMenu() const { return !this->pMenuPath.get().path().isEmpty(); } -bool StatusNotifierItem::onlyMenu() const { return this->pIsMenu.get(); } - void StatusNotifierItem::display(QObject* parentWindow, qint32 relativeX, qint32 relativeY) { if (!this->menuHandle()) { qCritical() << "No menu present for" << this; @@ -352,3 +336,30 @@ void StatusNotifierItem::display(QObject* parentWindow, qint32 relativeX, qint32 } } // namespace qs::service::sni + +namespace qs::dbus { +using namespace qs::service::sni; + +DBusResult DBusDataTransform::fromWire(const QString& wire) { + if (wire == QStringLiteral("Passive")) return DBusResult(Status::Passive); + if (wire == QStringLiteral("Active")) return DBusResult(Status::Active); + if (wire == QStringLiteral("NeedsAttention")) return DBusResult(Status::NeedsAttention); + + return DBusResult(QDBusError( + QDBusError::InvalidArgs, + QString("Nonconformant StatusNotifierItem Status: %1").arg(wire) + )); +} + +DBusResult DBusDataTransform::fromWire(const QString& wire) { + if (wire == "ApplicationStatus") return DBusResult(Category::ApplicationStatus); + if (wire == "SystemServices") return DBusResult(Category::SystemServices); + if (wire == "Hardware") return DBusResult(Category::Hardware); + + return DBusResult(QDBusError( + QDBusError::InvalidArgs, + QString("Nonconformant StatusNotifierItem Category: %1").arg(wire) + )); +} + +} // namespace qs::dbus diff --git a/src/services/status_notifier/item.hpp b/src/services/status_notifier/item.hpp index 4126424f..b82171ba 100644 --- a/src/services/status_notifier/item.hpp +++ b/src/services/status_notifier/item.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -54,6 +55,28 @@ enum Enum { Q_ENUM_NS(Enum); } // namespace Category +} // namespace qs::service::sni + +namespace qs::dbus { + +template <> +struct DBusDataTransform { + using Wire = QString; + using Data = qs::service::sni::Status::Enum; + static DBusResult fromWire(const QString& wire); +}; + +template <> +struct DBusDataTransform { + using Wire = QString; + using Data = qs::service::sni::Category::Enum; + static DBusResult fromWire(const QString& wire); +}; + +} // namespace qs::dbus + +namespace qs::service::sni { + class StatusNotifierItem; class TrayImageHandle: public QsImageHandle { @@ -74,24 +97,26 @@ public: class StatusNotifierItem: public QObject { Q_OBJECT; + // clang-format off /// A name unique to the application, such as its name. - Q_PROPERTY(QString id READ id NOTIFY idChanged); + Q_PROPERTY(QString id READ id NOTIFY idChanged BINDABLE bindableId); /// Text that describes the application. - Q_PROPERTY(QString title READ title NOTIFY titleChanged); - Q_PROPERTY(qs::service::sni::Status::Enum status READ status NOTIFY statusChanged); - Q_PROPERTY(qs::service::sni::Category::Enum category READ category NOTIFY categoryChanged); + Q_PROPERTY(QString title READ title NOTIFY titleChanged BINDABLE bindableTitle); + Q_PROPERTY(qs::service::sni::Status::Enum status READ status NOTIFY statusChanged BINDABLE bindableStatus); + Q_PROPERTY(qs::service::sni::Category::Enum category READ category NOTIFY categoryChanged BINDABLE bindableCategory); /// Icon source string, usable as an Image source. - Q_PROPERTY(QString icon READ iconId NOTIFY iconChanged); + Q_PROPERTY(QString icon READ icon NOTIFY iconChanged BINDABLE bindableIcon); Q_PROPERTY(QString tooltipTitle READ tooltipTitle NOTIFY tooltipTitleChanged); Q_PROPERTY(QString tooltipDescription READ tooltipDescription NOTIFY tooltipDescriptionChanged); /// If this tray item has an associated menu accessible via @@display() or @@menu. - Q_PROPERTY(bool hasMenu READ hasMenu NOTIFY hasMenuChanged); + Q_PROPERTY(bool hasMenu READ hasMenu NOTIFY hasMenuChanged BINDABLE bindableHasMenu); /// A handle to the menu associated with this tray item, if any. /// /// Can be displayed with @@Quickshell.QsMenuAnchor or @@Quickshell.QsMenuOpener. Q_PROPERTY(qs::dbus::dbusmenu::DBusMenuHandle* menu READ menuHandle NOTIFY hasMenuChanged); /// If this tray item only offers a menu and activation will do nothing. - Q_PROPERTY(bool onlyMenu READ onlyMenu NOTIFY onlyMenuChanged); + Q_PROPERTY(bool onlyMenu READ onlyMenu NOTIFY onlyMenuChanged BINDABLE bindableOnlyMenu); + // clang-format on QML_NAMED_ELEMENT(SystemTrayItem); QML_UNCREATABLE("SystemTrayItems can only be acquired from SystemTray"); @@ -100,7 +125,7 @@ public: [[nodiscard]] bool isValid() const; [[nodiscard]] bool isReady() const; - [[nodiscard]] QString iconId() const; + QS_BINDABLE_GETTER(QString, bIcon, icon, bindableIcon); [[nodiscard]] QPixmap createPixmap(const QSize& size) const; [[nodiscard]] dbus::dbusmenu::DBusMenuHandle* menuHandle(); @@ -114,21 +139,21 @@ public: /// Display a platform menu at the given location relative to the parent window. void display(QObject* parentWindow, qint32 relativeX, qint32 relativeY); - [[nodiscard]] QString id() const; - [[nodiscard]] QString title() const; - [[nodiscard]] Status::Enum status() const; - [[nodiscard]] Category::Enum category() const; - [[nodiscard]] QString tooltipTitle() const; - [[nodiscard]] QString tooltipDescription() const; - [[nodiscard]] bool hasMenu() const; - [[nodiscard]] bool onlyMenu() const; + QS_BINDABLE_GETTER(QString, bId, id, bindableId); + QS_BINDABLE_GETTER(QString, bTitle, title, bindableTitle); + QS_BINDABLE_GETTER(Status::Enum, bStatus, status, bindableStatus); + QS_BINDABLE_GETTER(Category::Enum, bCategory, category, bindableCategory); + [[nodiscard]] QString tooltipTitle() const { return this->bTooltip.value().title; }; + [[nodiscard]] QString tooltipDescription() const { return this->bTooltip.value().description; }; + QS_BINDABLE_GETTER(bool, bHasMenu, hasMenu, bindableHasMenu); + QS_BINDABLE_GETTER(bool, bIsMenu, onlyMenu, bindableOnlyMenu); signals: - void iconChanged(); void ready(); void idChanged(); void titleChanged(); + void iconChanged(); void statusChanged(); void categoryChanged(); void tooltipTitleChanged(); @@ -137,13 +162,13 @@ signals: void onlyMenuChanged(); private slots: - void updateIcon(); void onGetAllFinished(); void onGetAllFailed() const; - void onMenuPathChanged(); private: void updateMenuState(); + void updatePixmapIndex(); + void onMenuPathChanged(); DBusStatusNotifierItem* item = nullptr; TrayImageHandle imageHandle {this}; @@ -151,28 +176,53 @@ private: dbus::dbusmenu::DBusMenuHandle mMenuHandle {this}; - // bumped to inhibit caching - quint32 iconIndex = 0; QString watcherId; // clang-format off - dbus::DBusPropertyGroup properties; - dbus::DBusProperty pId {this->properties, "Id"}; - dbus::DBusProperty pTitle {this->properties, "Title"}; - dbus::DBusProperty pStatus {this->properties, "Status"}; - dbus::DBusProperty pCategory {this->properties, "Category"}; - dbus::DBusProperty pWindowId {this->properties, "WindowId"}; - dbus::DBusProperty pIconThemePath {this->properties, "IconThemePath", "", false}; - dbus::DBusProperty pIconName {this->properties, "IconName", "", false}; // IconPixmap may be set - dbus::DBusProperty pIconPixmaps {this->properties, "IconPixmap", {}, false}; // IconName may be set - dbus::DBusProperty pOverlayIconName {this->properties, "OverlayIconName"}; - dbus::DBusProperty pOverlayIconPixmaps {this->properties, "OverlayIconPixmap"}; - dbus::DBusProperty pAttentionIconName {this->properties, "AttentionIconName"}; - dbus::DBusProperty pAttentionIconPixmaps {this->properties, "AttentionIconPixmap"}; - dbus::DBusProperty pAttentionMovieName {this->properties, "AttentionMovieName", "", false}; - dbus::DBusProperty pTooltip {this->properties, "ToolTip"}; - dbus::DBusProperty pIsMenu {this->properties, "ItemIsMenu"}; - dbus::DBusProperty pMenuPath {this->properties, "Menu"}; + Q_OBJECT_BINDABLE_PROPERTY(StatusNotifierItem, QString, bId, &StatusNotifierItem::idChanged); + Q_OBJECT_BINDABLE_PROPERTY(StatusNotifierItem, QString, bTitle, &StatusNotifierItem::titleChanged); + Q_OBJECT_BINDABLE_PROPERTY(StatusNotifierItem, Status::Enum, bStatus, &StatusNotifierItem::statusChanged); + Q_OBJECT_BINDABLE_PROPERTY(StatusNotifierItem, Category::Enum, bCategory, &StatusNotifierItem::categoryChanged); + Q_OBJECT_BINDABLE_PROPERTY(StatusNotifierItem, QString, bIconThemePath); + Q_OBJECT_BINDABLE_PROPERTY(StatusNotifierItem, QString, bIconName); + Q_OBJECT_BINDABLE_PROPERTY(StatusNotifierItem, QString, bOverlayIconName); + Q_OBJECT_BINDABLE_PROPERTY(StatusNotifierItem, QString, bAttentionIconName); + Q_OBJECT_BINDABLE_PROPERTY(StatusNotifierItem, DBusSniIconPixmapList, bIconPixmaps); + Q_OBJECT_BINDABLE_PROPERTY(StatusNotifierItem, DBusSniIconPixmapList, bOverlayIconPixmaps); + Q_OBJECT_BINDABLE_PROPERTY(StatusNotifierItem, DBusSniIconPixmapList, bAttentionIconPixmaps); + Q_OBJECT_BINDABLE_PROPERTY(StatusNotifierItem, QString, bAttentionMovieName); + Q_OBJECT_BINDABLE_PROPERTY(StatusNotifierItem, DBusSniTooltip, bTooltip); + Q_OBJECT_BINDABLE_PROPERTY(StatusNotifierItem, bool, bIsMenu); + Q_OBJECT_BINDABLE_PROPERTY(StatusNotifierItem, QDBusObjectPath, bMenuPath); + Q_OBJECT_BINDABLE_PROPERTY(StatusNotifierItem, bool, bHasMenu, &StatusNotifierItem::hasMenuChanged); + + QS_BINDING_SUBSCRIBE_METHOD(StatusNotifierItem, bIconThemePath, updatePixmapIndex, onValueChanged); + QS_BINDING_SUBSCRIBE_METHOD(StatusNotifierItem, bIconName, updatePixmapIndex, onValueChanged); + QS_BINDING_SUBSCRIBE_METHOD(StatusNotifierItem, bOverlayIconName, updatePixmapIndex, onValueChanged); + QS_BINDING_SUBSCRIBE_METHOD(StatusNotifierItem, bAttentionIconName, updatePixmapIndex, onValueChanged); + QS_BINDING_SUBSCRIBE_METHOD(StatusNotifierItem, bIconPixmaps, updatePixmapIndex, onValueChanged); + QS_BINDING_SUBSCRIBE_METHOD(StatusNotifierItem, bOverlayIconPixmaps, updatePixmapIndex, onValueChanged); + QS_BINDING_SUBSCRIBE_METHOD(StatusNotifierItem, bAttentionIconPixmaps, updatePixmapIndex, onValueChanged); + QS_BINDING_SUBSCRIBE_METHOD(StatusNotifierItem, bMenuPath, onMenuPathChanged, onValueChanged); + Q_OBJECT_BINDABLE_PROPERTY(StatusNotifierItem, quint32, pixmapIndex); + Q_OBJECT_BINDABLE_PROPERTY(StatusNotifierItem, QString, bIcon, &StatusNotifierItem::iconChanged); + + QS_DBUS_BINDABLE_PROPERTY_GROUP(StatusNotifierItem, properties); + QS_DBUS_PROPERTY_BINDING(StatusNotifierItem, pId, bId, properties, "Id"); + QS_DBUS_PROPERTY_BINDING(StatusNotifierItem, pTitle, bTitle, properties, "Title"); + QS_DBUS_PROPERTY_BINDING(StatusNotifierItem, pStatus, bStatus, properties, "Status"); + QS_DBUS_PROPERTY_BINDING(StatusNotifierItem, pCategory, bCategory, properties, "Category"); + QS_DBUS_PROPERTY_BINDING(StatusNotifierItem, pIconThemePath, bIconThemePath, properties, "IconThemePath", false); + QS_DBUS_PROPERTY_BINDING(StatusNotifierItem, pIconName, bIconName, properties, "IconName", false); + QS_DBUS_PROPERTY_BINDING(StatusNotifierItem, pIconPixmaps, bIconPixmaps, properties, "IconPixmap", false); + QS_DBUS_PROPERTY_BINDING(StatusNotifierItem, pOverlayIconName, bOverlayIconName, properties, "OverlayIconName"); + QS_DBUS_PROPERTY_BINDING(StatusNotifierItem, pOverlayIconPixmaps, bOverlayIconPixmaps, properties, "OverlayIconPixmap"); + QS_DBUS_PROPERTY_BINDING(StatusNotifierItem, pAttentionIconName, bAttentionIconName, properties, "AttentionIconName"); + QS_DBUS_PROPERTY_BINDING(StatusNotifierItem, pAttentionIconPixmaps, bAttentionIconPixmaps, properties, "AttentionIconPixmap"); + QS_DBUS_PROPERTY_BINDING(StatusNotifierItem, pAttentionMovieName, bAttentionMovieName, properties, "AttentionMovieName", false); + QS_DBUS_PROPERTY_BINDING(StatusNotifierItem, pTooltip, bTooltip, properties, "ToolTip"); + QS_DBUS_PROPERTY_BINDING(StatusNotifierItem, pIsMenu, bIsMenu, properties, "ItemIsMenu"); + QS_DBUS_PROPERTY_BINDING(StatusNotifierItem, pMenuPath, bMenuPath, properties, "Menu"); // clang-format on };