/* BEGIN_COMMON_COPYRIGHT_HEADER * (c)LGPL2+ * * LXDE-Qt - a lightweight, Qt based, desktop toolset * http://lxqt.org * * Copyright: 2015 LXQt team * Authors: * Balázs Béla * Paulo Lieuthier * * This program or library is free software; you can redistribute it * and/or modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General * Public License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA * * END_COMMON_COPYRIGHT_HEADER */ #include "statusnotifierbutton.h" #include #include #include #include "../panel/ilxqtpanelplugin.h" #include "sniasync.h" StatusNotifierButton::StatusNotifierButton(QString service, QString objectPath, ILXQtPanelPlugin* plugin, QWidget *parent) : QToolButton(parent), mMenu(nullptr), mStatus(Passive), mFallbackIcon(QIcon::fromTheme("application-x-executable")), mPlugin(plugin) { interface = new SniAsync(service, objectPath, QDBusConnection::sessionBus(), this); connect(interface, &SniAsync::NewIcon, this, &StatusNotifierButton::newIcon); connect(interface, &SniAsync::NewOverlayIcon, this, &StatusNotifierButton::newOverlayIcon); connect(interface, &SniAsync::NewAttentionIcon, this, &StatusNotifierButton::newAttentionIcon); connect(interface, &SniAsync::NewToolTip, this, &StatusNotifierButton::newToolTip); connect(interface, &SniAsync::NewStatus, this, &StatusNotifierButton::newStatus); interface->propertyGetAsync(QLatin1String("Menu"), [this] (QDBusObjectPath path) { if (!path.path().isEmpty()) { mMenu = (new DBusMenuImporter(interface->service(), path.path(), this))->menu(); dynamic_cast(*mMenu).setParent(this); mMenu->setObjectName(QLatin1String("StatusNotifierMenu")); } }); interface->propertyGetAsync(QLatin1String("Status"), [this] (QString status) { newStatus(status); }); interface->propertyGetAsync(QLatin1String("IconThemePath"), [this] (QString value) { mThemePath = value; //do the logic of icons after we've got the theme path refetchIcon(Active); refetchIcon(Passive); refetchIcon(NeedsAttention); }); newToolTip(); } StatusNotifierButton::~StatusNotifierButton() { delete interface; } void StatusNotifierButton::newIcon() { refetchIcon(Passive); } void StatusNotifierButton::newOverlayIcon() { refetchIcon(Active); } void StatusNotifierButton::newAttentionIcon() { refetchIcon(NeedsAttention); } void StatusNotifierButton::refetchIcon(Status status) { QString nameProperty, pixmapProperty; if (status == Active) { nameProperty = QLatin1String("OverlayIconName"); pixmapProperty = QLatin1String("OverlayIconPixmap"); } else if (status == NeedsAttention) { nameProperty = QLatin1String("AttentionIconName"); pixmapProperty = QLatin1String("AttentionIconPixmap"); } else // status == Passive { nameProperty = QLatin1String("IconName"); pixmapProperty = QLatin1String("IconPixmap"); } interface->propertyGetAsync(nameProperty, [this, status, pixmapProperty] (QString iconName) { QIcon nextIcon; if (!iconName.isEmpty()) { if (QIcon::hasThemeIcon(iconName)) nextIcon = QIcon::fromTheme(iconName); else { QDir themeDir(mThemePath); if (themeDir.exists()) { if (themeDir.exists(iconName + ".png")) nextIcon.addFile(themeDir.filePath(iconName + ".png")); if (themeDir.cd("hicolor") || (themeDir.cd("icons") && themeDir.cd("hicolor"))) { QStringList sizes = themeDir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot); foreach (QString dir, sizes) { QStringList dirs = QDir(themeDir.filePath(dir)).entryList(QDir::AllDirs | QDir::NoDotAndDotDot); foreach (QString innerDir, dirs) { QString file = themeDir.absolutePath() + "/" + dir + "/" + innerDir + "/" + iconName + ".png"; if (QFile::exists(file)) nextIcon.addFile(file); } } } } } switch (status) { case Active: mOverlayIcon = nextIcon; break; case NeedsAttention: mAttentionIcon = nextIcon; break; case Passive: mIcon = nextIcon; break; } resetIcon(); } else { interface->propertyGetAsync(pixmapProperty, [this, status, pixmapProperty] (IconPixmapList iconPixmaps) { if (iconPixmaps.empty()) return; QIcon nextIcon; for (IconPixmap iconPixmap: iconPixmaps) { if (!iconPixmap.bytes.isNull()) { QImage image((uchar*) iconPixmap.bytes.data(), iconPixmap.width, iconPixmap.height, QImage::Format_ARGB32); const uchar *end = image.constBits() + image.byteCount(); uchar *dest = reinterpret_cast(iconPixmap.bytes.data()); for (const uchar *src = image.constBits(); src < end; src += 4, dest += 4) qToUnaligned(qToBigEndian(qFromUnaligned(src)), dest); nextIcon.addPixmap(QPixmap::fromImage(image)); } } switch (status) { case Active: mOverlayIcon = nextIcon; break; case NeedsAttention: mAttentionIcon = nextIcon; break; case Passive: mIcon = nextIcon; break; } resetIcon(); }); } }); } void StatusNotifierButton::newToolTip() { interface->propertyGetAsync(QLatin1String("ToolTip"), [this] (ToolTip tooltip) { QString toolTipTitle = tooltip.title; if (!toolTipTitle.isEmpty()) setToolTip(toolTipTitle); else interface->propertyGetAsync(QLatin1String("Title"), [this] (QString title) { // we should get here only in case the ToolTip.title was empty if (!title.isEmpty()) setToolTip(title); }); }); } void StatusNotifierButton::newStatus(QString status) { Status newStatus; if (status == QLatin1String("Passive")) newStatus = Passive; else if (status == QLatin1String("Active")) newStatus = Active; else newStatus = NeedsAttention; if (mStatus == newStatus) return; mStatus = newStatus; resetIcon(); } void StatusNotifierButton::contextMenuEvent(QContextMenuEvent* event) { //XXX: avoid showing of parent's context menu, we are (optionaly) providing context menu on mouseReleaseEvent //QWidget::contextMenuEvent(event); } void StatusNotifierButton::mouseReleaseEvent(QMouseEvent *event) { if (event->button() == Qt::LeftButton) interface->Activate(QCursor::pos().x(), QCursor::pos().y()); else if (event->button() == Qt::MidButton) interface->SecondaryActivate(QCursor::pos().x(), QCursor::pos().y()); else if (Qt::RightButton == event->button()) { if (mMenu) mMenu->popup(QCursor::pos()); else interface->ContextMenu(QCursor::pos().x(), QCursor::pos().y()); } QToolButton::mouseReleaseEvent(event); } void StatusNotifierButton::wheelEvent(QWheelEvent *event) { interface->Scroll(event->delta(), "vertical"); } void StatusNotifierButton::resetIcon() { if (mStatus == Active && !mOverlayIcon.isNull()) setIcon(mOverlayIcon); else if (mStatus == NeedsAttention && !mAttentionIcon.isNull()) setIcon(mAttentionIcon); else if (!mIcon.isNull()) // mStatus == Passive setIcon(mIcon); else if (!mOverlayIcon.isNull()) setIcon(mOverlayIcon); else if (!mAttentionIcon.isNull()) setIcon(mAttentionIcon); else setIcon(mFallbackIcon); }