Compare commits

...

4 Commits

Author SHA1 Message Date
Alf Gaida
8594ea0414 Adding upstream version 0.10.96~8-g411f696. 2016-07-19 15:42:18 +02:00
Alf Gaida
b34de2c23b Adding upstream version 0.10.0. 2015-11-03 00:43:30 +01:00
Alf Gaida
4ca5973d60 Adding upstream version 0.9.0+20151025. 2015-10-31 01:09:15 +01:00
Alf Gaida
88b1696810 Adding upstream version 0.9.0+20150924. 2015-09-25 19:21:58 +02:00
16 changed files with 1296 additions and 246 deletions

2
.gitignore vendored
View File

@ -1,2 +0,0 @@
build
*.kdev4

View File

@ -3,9 +3,7 @@ Upstream Authors:
Hong Jen Yee (PCMan) <pcman.tw@gmail.com> Hong Jen Yee (PCMan) <pcman.tw@gmail.com>
Copyright: Copyright:
Copyright (c) 2013-2014 LXQt team Copyright (c) 2013-2016 LXQt team
License: GPL-2 and LGPL-2.1+ License: LGPL-2.1+
The full text of the licenses can be found in the 'COPYING' file. The full text of the licenses can be found in the 'COPYING' file.
Based on source code from the Qt 4.8 Project by Digia Plc

View File

@ -7,6 +7,8 @@ set(CMAKE_AUTOMOC ON)
find_package(Qt5Widgets REQUIRED QUIET) find_package(Qt5Widgets REQUIRED QUIET)
find_package(Qt5LinguistTools REQUIRED QUIET) find_package(Qt5LinguistTools REQUIRED QUIET)
find_package(Qt5DBus REQUIRED QUIET)
find_package(dbusmenu-qt5 REQUIRED QUIET)
find_package(lxqt REQUIRED QUIET) find_package(lxqt REQUIRED QUIET)

View File

@ -1,9 +1,8 @@
GNU LESSER GENERAL PUBLIC LICENSE GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999 Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc. Copyright (C) 1991, 1999 Free Software Foundation, Inc.
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed. of this license document, but changing it is not allowed.
@ -23,8 +22,7 @@ specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations strategy to use in any particular case, based on the explanations below.
below.
When we speak of free software, we are referring to freedom of use, When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that not price. Our General Public Licenses are designed to make sure that
@ -89,9 +87,9 @@ libraries. However, the Lesser license provides advantages in certain
special circumstances. special circumstances.
For example, on rare occasions, there may be a special need to For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it encourage the widest possible use of a certain library, so that it becomes
becomes a de-facto standard. To achieve this, non-free programs must a de-facto standard. To achieve this, non-free programs must be
be allowed to use the library. A more frequent case is that a free allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License. software only, so we use the Lesser General Public License.
@ -138,8 +136,8 @@ included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for "Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control interface definition files, plus the scripts used to control compilation
compilation and installation of the library. and installation of the library.
Activities other than copying, distribution and modification are not Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of covered by this License; they are outside its scope. The act of
@ -305,10 +303,10 @@ of these things:
the user installs one, as long as the modified version is the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with. interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at least c) Accompany the work with a written offer, valid for at
three years, to give the same user the materials specified in least three years, to give the same user the materials
Subsection 6a, above, for a charge no more than the cost of specified in Subsection 6a, above, for a charge no more
performing this distribution. than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above from a designated place, offer equivalent access to copy the above
@ -386,10 +384,9 @@ all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library. refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under If any portion of this section is held invalid or unenforceable under any
any particular circumstance, the balance of the section is intended to particular circumstance, the balance of the section is intended to apply,
apply, and the section as a whole is intended to apply in other and the section as a whole is intended to apply in other circumstances.
circumstances.
It is not the purpose of this section to induce you to infringe any It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any patents or other property right claims or to contest validity of any
@ -407,11 +404,11 @@ be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in 12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License original copyright holder who places the Library under this License may add
may add an explicit geographical distribution limitation excluding those an explicit geographical distribution limitation excluding those countries,
countries, so that distribution is permitted only in or among so that distribution is permitted only in or among countries not thus
countries not thus excluded. In such case, this License incorporates excluded. In such case, this License incorporates the limitation as if
the limitation as if written in the body of this License. written in the body of this License.
13. The Free Software Foundation may publish revised and/or new 13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time. versions of the Lesser General Public License from time to time.

View File

@ -1,4 +1,6 @@
libqtlxqt - LXQt system integration plugin for Qt. # libqtlxqt
LXQt system integration plugin for Qt.
With this plugin, all Qt-based programs can adopt settings of With this plugin, all Qt-based programs can adopt settings of
LXQt, such as the icon theme. LXQt, such as the icon theme.

View File

@ -3,15 +3,35 @@ include_directories(
"${CMAKE_CURRENT_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}"
) )
set(qtlxqt_HDRS
lxqtplatformtheme.h
lxqtsystemtrayicon.h
statusnotifieritem/statusnotifieritem.h
statusnotifieritem/dbustypes.h
)
set(qtlxqt_SRCS set(qtlxqt_SRCS
main.cpp main.cpp
lxqtplatformtheme.cpp lxqtplatformtheme.cpp
lxqtsystemtrayicon.cpp
statusnotifieritem/statusnotifieritem.cpp
statusnotifieritem/dbustypes.cpp
) )
add_library(qtlxqt SHARED ${qtlxqt_SRCS}) qt5_add_dbus_adaptor(qtlxqt_SRCS
statusnotifieritem/org.kde.StatusNotifierItem.xml
statusnotifieritem/statusnotifieritem.h
StatusNotifierItem
)
add_library(qtlxqt SHARED ${qtlxqt_HDRS} ${qtlxqt_SRCS})
target_link_libraries(qtlxqt target_link_libraries(qtlxqt
Qt5::Widgets Qt5::Widgets
Qt5::DBus
dbusmenu-qt5
lxqt
Qt5XdgIconLoader
) )
# there is no standard way to get the plugin dir of Qt5 with cmake # there is no standard way to get the plugin dir of Qt5 with cmake

View File

@ -44,12 +44,11 @@
#include <QFileInfo> #include <QFileInfo>
#include <QFileSystemWatcher> #include <QFileSystemWatcher>
#include <QStyle> #include <QStyle>
#include "qiconloader_p.h" #include <private/xdgiconloader/xdgiconloader_p.h>
LXQtPlatformTheme::LXQtPlatformTheme(): LXQtPlatformTheme::LXQtPlatformTheme():
settingsWatcher_(NULL) settingsWatcher_(NULL)
{ {
// qDebug() << "LXQT Platform Theme loaded";
// When the plugin is loaded, it seems that the app is not yet running and // When the plugin is loaded, it seems that the app is not yet running and
// QThread environment is not completely set up. So creating filesystem watcher // QThread environment is not completely set up. So creating filesystem watcher
// does not work since it uses QSocketNotifier internally which can only be // does not work since it uses QSocketNotifier internally which can only be
@ -106,14 +105,12 @@ void LXQtPlatformTheme::loadSettings() {
if(!fontStr_.isEmpty()) { if(!fontStr_.isEmpty()) {
if(font_.fromString(fontStr_)) if(font_.fromString(fontStr_))
QApplication::setFont(font_); // it seems that we need to do this manually. QApplication::setFont(font_); // it seems that we need to do this manually.
// qDebug() << "font: " << font_.toString();
} }
// FixedFont // FixedFont
fixedFontStr_ = settings.value(QLatin1String("fixedFont")).toString(); fixedFontStr_ = settings.value(QLatin1String("fixedFont")).toString();
if(!fixedFontStr_.isEmpty()) { if(!fixedFontStr_.isEmpty()) {
fixedFont_.fromString(fixedFontStr_); fixedFont_.fromString(fixedFontStr_);
// qDebug() << "fixedFont: " << fixedFont_.toString();
} }
// mouse // mouse
@ -165,7 +162,7 @@ void LXQtPlatformTheme::onSettingsChanged() {
} }
if(iconTheme_ != oldIconTheme) { // the icon theme is changed if(iconTheme_ != oldIconTheme) { // the icon theme is changed
QIconLoader::instance()->updateSystemTheme(); // this is a private internal API of Qt5. XdgIconLoader::instance()->updateSystemTheme(); // this is a private internal API of Qt5.
} }
// if font is changed // if font is changed
@ -214,10 +211,9 @@ const QPalette *LXQtPlatformTheme::palette(Palette type) const {
} }
const QFont *LXQtPlatformTheme::font(Font type) const { const QFont *LXQtPlatformTheme::font(Font type) const {
// qDebug() << "font()" << type << SystemFont;
if(type == SystemFont && !fontStr_.isEmpty()) { if(type == SystemFont && !fontStr_.isEmpty()) {
// NOTE: for some reason, this is not called by Qt when program startup. // NOTE: for some reason, this is not called by Qt when program startup.
// So we do QApplication::setFont() manually. // So we do QApplication::setFont() manually.
return &font_; return &font_;
} }
else if(type == FixedFont && !fixedFontStr_.isEmpty()) { else if(type == FixedFont && !fixedFontStr_.isEmpty()) {
@ -227,7 +223,6 @@ const QFont *LXQtPlatformTheme::font(Font type) const {
} }
QVariant LXQtPlatformTheme::themeHint(ThemeHint hint) const { QVariant LXQtPlatformTheme::themeHint(ThemeHint hint) const {
// qDebug() << "themeHint" << hint;
switch (hint) { switch (hint) {
case CursorFlashTime: case CursorFlashTime:
return cursorFlashTime_; return cursorFlashTime_;
@ -258,14 +253,12 @@ QVariant LXQtPlatformTheme::themeHint(ThemeHint hint) const {
case ItemViewActivateItemOnSingleClick: case ItemViewActivateItemOnSingleClick:
return QVariant(singleClickActivate_); return QVariant(singleClickActivate_);
case SystemIconThemeName: case SystemIconThemeName:
// qDebug() << "iconTheme" << iconTheme_;
return iconTheme_; return iconTheme_;
case SystemIconFallbackThemeName: case SystemIconFallbackThemeName:
return "hicolor"; return "hicolor";
case IconThemeSearchPaths: case IconThemeSearchPaths:
return xdgIconThemePaths(); return xdgIconThemePaths();
case StyleNames: case StyleNames:
// qDebug() << "StyleNames";
return QStringList() << style_; return QStringList() << style_;
case WindowAutoPlacement: case WindowAutoPlacement:
break; break;
@ -291,35 +284,50 @@ QVariant LXQtPlatformTheme::themeHint(ThemeHint hint) const {
break; break;
case ContextMenuOnMouseRelease: case ContextMenuOnMouseRelease:
break; break;
#if QT_VERSION >= QT_VERSION_CHECK(5, 3, 0)
// this was introduced in Qt 5.3.
case MousePressAndHoldInterval: case MousePressAndHoldInterval:
break; break;
case MouseDoubleClickDistance: case MouseDoubleClickDistance:
break; break;
#endif
default: default:
break; break;
} }
return QPlatformTheme::themeHint(hint); return QPlatformTheme::themeHint(hint);
} }
QIconEngine *LXQtPlatformTheme::createIconEngine(const QString &iconName) const
{
return new XdgIconLoaderEngine(iconName);
}
// Helper to return the icon theme paths from XDG. // Helper to return the icon theme paths from XDG.
QStringList LXQtPlatformTheme::xdgIconThemePaths() const QStringList LXQtPlatformTheme::xdgIconThemePaths() const
{ {
QStringList paths; QStringList paths;
QStringList xdgDirs;
// Add home directory first in search path // Add home directory first in search path
const QFileInfo homeIconDir(QDir::homePath() + QStringLiteral("/.icons")); const QFileInfo homeIconDir(QDir::homePath() + QStringLiteral("/.icons"));
if (homeIconDir.isDir()) if (homeIconDir.isDir())
paths.prepend(homeIconDir.absoluteFilePath()); paths.prepend(homeIconDir.absoluteFilePath());
QString xdgDirString = QFile::decodeName(qgetenv("XDG_DATA_DIRS")); QString xdgDataHome = QFile::decodeName(qgetenv("XDG_DATA_HOME"));
if (xdgDirString.isEmpty()) if (xdgDataHome.isEmpty())
xdgDirString = QLatin1String("/usr/local/share/:/usr/share/"); xdgDataHome = QDir::homePath() + QLatin1String("/.local/share");
foreach (const QString &xdgDir, xdgDirString.split(QLatin1Char(':'))) { xdgDirs.append(xdgDataHome);
const QFileInfo xdgIconsDir(xdgDir + QStringLiteral("/icons"));
if (xdgIconsDir.isDir()) QString xdgDataDirs = QFile::decodeName(qgetenv("XDG_DATA_DIRS"));
paths.append(xdgIconsDir.absoluteFilePath()); if (xdgDataDirs.isEmpty())
xdgDataDirs = QLatin1String("/usr/local/share/:/usr/share/");
xdgDirs.append(xdgDataDirs);
foreach (const QString &s, xdgDirs) {
const QStringList r = s.split(QLatin1Char(':'), QString::SkipEmptyParts);
foreach (const QString &xdgDir, r) {
const QFileInfo xdgIconsDir(xdgDir + QStringLiteral("/icons"));
if (xdgIconsDir.isDir())
paths.append(xdgIconsDir.absoluteFilePath());
}
} }
paths.removeDuplicates();
return paths; return paths;
} }

View File

@ -28,6 +28,8 @@
#ifndef LXQTPLATFORMTHEME_H #ifndef LXQTPLATFORMTHEME_H
#define LXQTPLATFORMTHEME_H #define LXQTPLATFORMTHEME_H
#include "lxqtsystemtrayicon.h"
#include <qpa/qplatformtheme.h> // this private header is subject to changes #include <qpa/qplatformtheme.h> // this private header is subject to changes
#include <QtGlobal> #include <QtGlobal>
#include <QVariant> #include <QVariant>
@ -54,11 +56,23 @@ public:
virtual QVariant themeHint(ThemeHint hint) const; virtual QVariant themeHint(ThemeHint hint) const;
QPlatformSystemTrayIcon *createPlatformSystemTrayIcon() const
{
auto trayIcon = new LXQtSystemTrayIcon;
if (trayIcon->isSystemTrayAvailable())
return trayIcon;
else
{
delete trayIcon;
return nullptr;
}
}
// virtual QPixmap standardPixmap(StandardPixmap sp, const QSizeF &size) const; // virtual QPixmap standardPixmap(StandardPixmap sp, const QSizeF &size) const;
// virtual QPixmap fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &size, // virtual QPixmap fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &size,
// QPlatformTheme::IconOptions iconOptions = 0) const; // QPlatformTheme::IconOptions iconOptions = 0) const;
// virtual QIconEngine *createIconEngine(const QString &iconName) const; virtual QIconEngine *createIconEngine(const QString &iconName) const;
// virtual QList<QKeySequence> keyBindings(QKeySequence::StandardKey key) const; // virtual QList<QKeySequence> keyBindings(QKeySequence::StandardKey key) const;

382
src/lxqtsystemtrayicon.cpp Normal file
View File

@ -0,0 +1,382 @@
/* BEGIN_COMMON_COPYRIGHT_HEADER
* (c)LGPL2+
*
* LXQt - a lightweight, Qt based, desktop toolset
* http://lxqt.org/
*
* Copyright: 2015 LXQt team
* Authors:
* Paulo Lieuthier <paulolieuthier@gmail.com>
*
* 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 "lxqtsystemtrayicon.h"
#include <QAction>
#include <QIcon>
#include <QMenu>
#include <QRect>
#include <QApplication>
#include <QDBusMetaType>
#include <QDBusInterface>
SystemTrayMenu::SystemTrayMenu()
: QPlatformMenu(),
m_tag(0),
m_menu(new QMenu())
{
connect(m_menu.data(), &QMenu::aboutToShow, this, &QPlatformMenu::aboutToShow);
connect(m_menu.data(), &QMenu::aboutToHide, this, &QPlatformMenu::aboutToHide);
}
SystemTrayMenu::~SystemTrayMenu()
{
if (m_menu)
m_menu->deleteLater();
}
QPlatformMenuItem *SystemTrayMenu::createMenuItem() const
{
return new SystemTrayMenuItem();
}
void SystemTrayMenu::insertMenuItem(QPlatformMenuItem *menuItem, QPlatformMenuItem *before)
{
if (SystemTrayMenuItem *ours = qobject_cast<SystemTrayMenuItem*>(menuItem))
{
bool inserted = false;
if (SystemTrayMenuItem *oursBefore = qobject_cast<SystemTrayMenuItem*>(before))
{
for (auto it = m_items.begin(); it != m_items.end(); ++it)
{
if (*it == oursBefore)
{
m_items.insert(it, ours);
if (m_menu)
m_menu->insertAction(oursBefore->action(), ours->action());
inserted = true;
break;
}
}
}
if (!inserted)
{
m_items.append(ours);
if (m_menu)
m_menu->addAction(ours->action());
}
}
}
QPlatformMenuItem *SystemTrayMenu::menuItemAt(int position) const
{
if (position < m_items.size())
return m_items.at(position);
return nullptr;
}
QPlatformMenuItem *SystemTrayMenu::menuItemForTag(quintptr tag) const
{
auto it = std::find_if(m_items.constBegin(), m_items.constEnd(), [tag] (SystemTrayMenuItem *item)
{
return item->tag() == tag;
});
if (it != m_items.constEnd())
return *it;
return nullptr;
}
void SystemTrayMenu::removeMenuItem(QPlatformMenuItem *menuItem)
{
if (SystemTrayMenuItem *ours = qobject_cast<SystemTrayMenuItem*>(menuItem))
{
m_items.removeOne(ours);
if (ours->action() && m_menu)
m_menu->removeAction(ours->action());
}
}
void SystemTrayMenu::setEnabled(bool enabled)
{
if (!m_menu)
return;
m_menu->setEnabled(enabled);
}
void SystemTrayMenu::setIcon(const QIcon &icon)
{
if (!m_menu)
return;
m_menu->setIcon(icon);
}
void SystemTrayMenu::setTag(quintptr tag)
{
m_tag = tag;
}
void SystemTrayMenu::setText(const QString &text)
{
if (!m_menu)
return;
m_menu->setTitle(text);
}
void SystemTrayMenu::setVisible(bool visible)
{
if (!m_menu)
return;
m_menu->setVisible(visible);
}
void SystemTrayMenu::syncMenuItem(QPlatformMenuItem *)
{
// Nothing to do
}
void SystemTrayMenu::syncSeparatorsCollapsible(bool enable)
{
if (!m_menu)
return;
m_menu->setSeparatorsCollapsible(enable);
}
quintptr SystemTrayMenu::tag() const
{
return m_tag;
}
QMenu *SystemTrayMenu::menu() const
{
return m_menu.data();
}
SystemTrayMenuItem::SystemTrayMenuItem()
: QPlatformMenuItem(),
m_tag(0),
m_action(new QAction(this))
{
connect(m_action, &QAction::triggered, this, &QPlatformMenuItem::activated);
connect(m_action, &QAction::hovered, this, &QPlatformMenuItem::hovered);
}
SystemTrayMenuItem::~SystemTrayMenuItem()
{
}
void SystemTrayMenuItem::setCheckable(bool checkable)
{
m_action->setCheckable(checkable);
}
void SystemTrayMenuItem::setChecked(bool isChecked)
{
m_action->setChecked(isChecked);
}
void SystemTrayMenuItem::setEnabled(bool enabled)
{
m_action->setEnabled(enabled);
}
void SystemTrayMenuItem::setFont(const QFont &font)
{
m_action->setFont(font);
}
void SystemTrayMenuItem::setIcon(const QIcon &icon)
{
m_action->setIcon(icon);
}
void SystemTrayMenuItem::setIsSeparator(bool isSeparator)
{
m_action->setSeparator(isSeparator);
}
void SystemTrayMenuItem::setMenu(QPlatformMenu *menu)
{
if (SystemTrayMenu *ourMenu = qobject_cast<SystemTrayMenu *>(menu))
m_action->setMenu(ourMenu->menu());
}
void SystemTrayMenuItem::setRole(QPlatformMenuItem::MenuRole)
{
}
void SystemTrayMenuItem::setShortcut(const QKeySequence &shortcut)
{
m_action->setShortcut(shortcut);
}
void SystemTrayMenuItem::setTag(quintptr tag)
{
m_tag = tag;
}
void SystemTrayMenuItem::setText(const QString &text)
{
m_action->setText(text);
}
void SystemTrayMenuItem::setVisible(bool isVisible)
{
m_action->setVisible(isVisible);
}
void SystemTrayMenuItem::setIconSize(int)
{
}
quintptr SystemTrayMenuItem::tag() const
{
return m_tag;
}
QAction *SystemTrayMenuItem::action() const
{
return m_action;
}
LXQtSystemTrayIcon::LXQtSystemTrayIcon()
: QPlatformSystemTrayIcon(),
mSni(nullptr)
{
// register types
qDBusRegisterMetaType<ToolTip>();
qDBusRegisterMetaType<IconPixmap>();
qDBusRegisterMetaType<IconPixmapList>();
}
LXQtSystemTrayIcon::~LXQtSystemTrayIcon()
{
}
void LXQtSystemTrayIcon::init()
{
if (!mSni)
{
mSni = new StatusNotifierItem(QString::number(QCoreApplication::applicationPid()), this);
mSni->setTitle(QApplication::applicationDisplayName());
// default menu
QPlatformMenu *menu = createMenu();
menu->setParent(mSni);
QPlatformMenuItem *menuItem = menu->createMenuItem();
menuItem->setParent(menu);
menuItem->setText(tr("Quit"));
menuItem->setIcon(QIcon::fromTheme("application-exit"));
connect(menuItem, &QPlatformMenuItem::activated, qApp, &QApplication::quit);
menu->insertMenuItem(menuItem, nullptr);
updateMenu(menu);
connect(mSni, &StatusNotifierItem::activateRequested, [this](const QPoint &)
{
emit activated(QPlatformSystemTrayIcon::Trigger);
});
connect(mSni, &StatusNotifierItem::secondaryActivateRequested, [this](const QPoint &)
{
emit activated(QPlatformSystemTrayIcon::MiddleClick);
});
}
}
void LXQtSystemTrayIcon::cleanup()
{
delete mSni;
mSni = nullptr;
}
void LXQtSystemTrayIcon::updateIcon(const QIcon &icon)
{
if (!mSni)
return;
if (icon.name().isEmpty())
{
mSni->setIconByPixmap(icon);
mSni->setToolTipIconByPixmap(icon);
}
else
{
mSni->setIconByName(icon.name());
mSni->setToolTipIconByName(icon.name());
}
}
void LXQtSystemTrayIcon::updateToolTip(const QString &tooltip)
{
if (!mSni)
return;
mSni->setToolTipTitle(tooltip);
}
void LXQtSystemTrayIcon::updateMenu(QPlatformMenu *menu)
{
if (!mSni)
return;
if (SystemTrayMenu *ourMenu = qobject_cast<SystemTrayMenu*>(menu))
mSni->setContextMenu(ourMenu->menu());
}
QPlatformMenu *LXQtSystemTrayIcon::createMenu() const
{
return new SystemTrayMenu();
}
QRect LXQtSystemTrayIcon::geometry() const
{
// StatusNotifierItem doesn't provide the geometry
return QRect();
}
void LXQtSystemTrayIcon::showMessage(const QString &title, const QString &msg,
const QIcon &icon, MessageIcon, int secs)
{
if (!mSni)
return;
mSni->showMessage(title, msg, icon.name(), secs);
}
bool LXQtSystemTrayIcon::isSystemTrayAvailable() const
{
QDBusInterface systrayHost("org.kde.StatusNotifierWatcher",
"/StatusNotifierWatcher",
"org.kde.StatusNotifierWatcher");
return systrayHost.isValid() && systrayHost.property("IsStatusNotifierHostRegistered").toBool();
}
bool LXQtSystemTrayIcon::supportsMessages() const
{
return true;
}

124
src/lxqtsystemtrayicon.h Normal file
View File

@ -0,0 +1,124 @@
/* BEGIN_COMMON_COPYRIGHT_HEADER
* (c)LGPL2+
*
* LXQt - a lightweight, Qt based, desktop toolset
* http://lxqt.org/
*
* Copyright: 2015 LXQt team
* Authors:
* Paulo Lieuthier <paulolieuthier@gmail.com>
*
* 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 */
#ifndef LXQTSYSTEMTRAYICON_H
#define LXQTSYSTEMTRAYICON_H
#include <qpa/qplatformmenu.h>
#include <qpa/qplatformsystemtrayicon.h>
#include "statusnotifieritem/statusnotifieritem.h"
class SystemTrayMenuItem;
class QAction;
class QMenu;
class SystemTrayMenu : public QPlatformMenu
{
Q_OBJECT
public:
SystemTrayMenu();
~SystemTrayMenu() Q_DECL_OVERRIDE;
void insertMenuItem(QPlatformMenuItem *menuItem, QPlatformMenuItem *before) Q_DECL_OVERRIDE;
QPlatformMenuItem *menuItemAt(int position) const Q_DECL_OVERRIDE;
QPlatformMenuItem *menuItemForTag(quintptr tag) const Q_DECL_OVERRIDE;
void removeMenuItem(QPlatformMenuItem *menuItem) Q_DECL_OVERRIDE;
void setEnabled(bool enabled) Q_DECL_OVERRIDE;
void setIcon(const QIcon &icon) Q_DECL_OVERRIDE;
void setTag(quintptr tag) Q_DECL_OVERRIDE;
void setText(const QString &text) Q_DECL_OVERRIDE;
void setVisible(bool visible) Q_DECL_OVERRIDE;
void syncMenuItem(QPlatformMenuItem *menuItem) Q_DECL_OVERRIDE;
void syncSeparatorsCollapsible(bool enable) Q_DECL_OVERRIDE;
quintptr tag() const Q_DECL_OVERRIDE;
QPlatformMenuItem *createMenuItem() const Q_DECL_OVERRIDE;
QMenu *menu() const;
private:
quintptr m_tag;
QPointer<QMenu> m_menu;
QList<SystemTrayMenuItem*> m_items;
};
class SystemTrayMenuItem : public QPlatformMenuItem
{
Q_OBJECT
public:
SystemTrayMenuItem();
~SystemTrayMenuItem() Q_DECL_OVERRIDE;
void setCheckable(bool checkable) Q_DECL_OVERRIDE;
void setChecked(bool isChecked) Q_DECL_OVERRIDE;
void setEnabled(bool enabled) Q_DECL_OVERRIDE;
void setFont(const QFont &font) Q_DECL_OVERRIDE;
void setIcon(const QIcon &icon) Q_DECL_OVERRIDE;
void setIsSeparator(bool isSeparator) Q_DECL_OVERRIDE;
void setMenu(QPlatformMenu *menu) Q_DECL_OVERRIDE;
void setRole(MenuRole role) Q_DECL_OVERRIDE;
void setShortcut(const QKeySequence &shortcut) Q_DECL_OVERRIDE;
void setTag(quintptr tag) Q_DECL_OVERRIDE;
void setText(const QString &text) Q_DECL_OVERRIDE;
void setVisible(bool isVisible) Q_DECL_OVERRIDE;
quintptr tag() const Q_DECL_OVERRIDE;
void setIconSize(int size)
#if (QT_VERSION >= QT_VERSION_CHECK(5, 4, 0))
Q_DECL_OVERRIDE
#endif
;
QAction *action() const;
private:
quintptr m_tag;
QAction *m_action;
};
class LXQtSystemTrayIcon : public QPlatformSystemTrayIcon
{
public:
LXQtSystemTrayIcon();
~LXQtSystemTrayIcon() Q_DECL_OVERRIDE;
void init() Q_DECL_OVERRIDE;
void cleanup() Q_DECL_OVERRIDE;
void updateIcon(const QIcon &icon) Q_DECL_OVERRIDE;
void updateToolTip(const QString &tooltip) Q_DECL_OVERRIDE;
void updateMenu(QPlatformMenu *menu) Q_DECL_OVERRIDE;
QRect geometry() const Q_DECL_OVERRIDE;
void showMessage(const QString &title, const QString &msg,
const QIcon &icon, MessageIcon iconType, int secs) Q_DECL_OVERRIDE;
bool isSystemTrayAvailable() const Q_DECL_OVERRIDE;
bool supportsMessages() const Q_DECL_OVERRIDE;
QPlatformMenu *createMenu() const Q_DECL_OVERRIDE;
private:
StatusNotifierItem *mSni;
};
#endif

View File

@ -1,194 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QICONLOADER_P_H
#define QICONLOADER_P_H
#include <QtCore/qglobal.h>
#ifndef QT_NO_ICON
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include <QtGui/QIcon>
#include <QtGui/QIconEngine>
#include <QtGui/QPixmapCache>
#include <private/qicon_p.h>
#include <private/qfactoryloader_p.h>
#include <QtCore/QHash>
QT_BEGIN_NAMESPACE
class QIconLoader;
struct QIconDirInfo
{
enum Type { Fixed, Scalable, Threshold };
QIconDirInfo(const QString &_path = QString()) :
path(_path),
size(0),
maxSize(0),
minSize(0),
threshold(0),
type(Threshold) {}
QString path;
short size;
short maxSize;
short minSize;
short threshold;
Type type : 4;
};
class QIconLoaderEngineEntry
{
public:
virtual ~QIconLoaderEngineEntry() {}
virtual QPixmap pixmap(const QSize &size,
QIcon::Mode mode,
QIcon::State state) = 0;
QString filename;
QIconDirInfo dir;
static int count;
};
struct ScalableEntry : public QIconLoaderEngineEntry
{
QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state);
QIcon svgIcon;
};
struct PixmapEntry : public QIconLoaderEngineEntry
{
QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state);
QPixmap basePixmap;
};
typedef QList<QIconLoaderEngineEntry*> QThemeIconEntries;
class QIconLoaderEngine : public QIconEngine
{
public:
QIconLoaderEngine(const QString& iconName = QString());
~QIconLoaderEngine();
void paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state);
QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state);
QSize actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state);
QIconEngine *clone() const;
bool read(QDataStream &in);
bool write(QDataStream &out) const;
private:
QString key() const;
bool hasIcon() const;
void ensureLoaded();
void virtual_hook(int id, void *data);
QIconLoaderEngineEntry *entryForSize(const QSize &size);
QIconLoaderEngine(const QIconLoaderEngine &other);
QThemeIconEntries m_entries;
QString m_iconName;
uint m_key;
friend class QIconLoader;
};
class QIconTheme
{
public:
QIconTheme(const QString &name);
QIconTheme() : m_valid(false) {}
QStringList parents() { return m_parents; }
QList <QIconDirInfo> keyList() { return m_keyList; }
QString contentDir() { return m_contentDir; }
bool isValid() { return m_valid; }
private:
QString m_contentDir;
QList <QIconDirInfo> m_keyList;
QStringList m_parents;
bool m_valid;
};
class Q_GUI_EXPORT QIconLoader : public QObject
{
public:
QIconLoader();
QThemeIconEntries loadIcon(const QString &iconName) const;
uint themeKey() const { return m_themeKey; }
QString themeName() const { return m_userTheme.isEmpty() ? m_systemTheme : m_userTheme; }
void setThemeName(const QString &themeName);
QIconTheme theme() { return themeList.value(themeName()); }
void setThemeSearchPath(const QStringList &searchPaths);
QStringList themeSearchPaths() const;
QIconDirInfo dirInfo(int dirindex);
static QIconLoader *instance();
void updateSystemTheme();
void invalidateKey() { m_themeKey++; }
void ensureInitialized();
private:
QThemeIconEntries findIconHelper(const QString &themeName,
const QString &iconName,
QStringList &visited) const;
uint m_themeKey;
bool m_supportsSvg;
bool m_initialized;
mutable QString m_userTheme;
mutable QString m_systemTheme;
mutable QStringList m_iconDirs;
mutable QHash <QString, QIconTheme> themeList;
};
QT_END_NAMESPACE
#endif // QT_NO_ICON
#endif // QICONLOADER_P_H

View File

@ -0,0 +1,75 @@
/* 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 <balazsbela[at]gmail.com>
* Paulo Lieuthier <paulolieuthier@gmail.com>
*
* 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 "dbustypes.h"
// Marshall the IconPixmap data into a D-Bus argument
QDBusArgument &operator<<(QDBusArgument &argument, const IconPixmap &icon)
{
argument.beginStructure();
argument << icon.width;
argument << icon.height;
argument << icon.bytes;
argument.endStructure();
return argument;
}
// Retrieve the ImageStruct data from the D-Bus argument
const QDBusArgument &operator>>(const QDBusArgument &argument, IconPixmap &icon)
{
argument.beginStructure();
argument >> icon.width;
argument >> icon.height;
argument >> icon.bytes;
argument.endStructure();
return argument;
}
// Marshall the ToolTip data into a D-Bus argument
QDBusArgument &operator<<(QDBusArgument &argument, const ToolTip &toolTip)
{
argument.beginStructure();
argument << toolTip.iconName;
argument << toolTip.iconPixmap;
argument << toolTip.title;
argument << toolTip.description;
argument.endStructure();
return argument;
}
// Retrieve the ToolTip data from the D-Bus argument
const QDBusArgument &operator>>(const QDBusArgument &argument, ToolTip &toolTip)
{
argument.beginStructure();
argument >> toolTip.iconName;
argument >> toolTip.iconPixmap;
argument >> toolTip.title;
argument >> toolTip.description;
argument.endStructure();
return argument;
}

View File

@ -0,0 +1,60 @@
/* 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 <balazsbela[at]gmail.com>
* Paulo Lieuthier <paulolieuthier@gmail.com>
*
* 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 <QDBusArgument>
#ifndef DBUSTYPES_H
#define DBUSTYPES_H
struct IconPixmap {
int width;
int height;
QByteArray bytes;
};
typedef QList<IconPixmap> IconPixmapList;
Q_DECLARE_METATYPE(IconPixmap)
Q_DECLARE_METATYPE(IconPixmapList)
struct ToolTip {
QString iconName;
QList<IconPixmap> iconPixmap;
QString title;
QString description;
};
Q_DECLARE_METATYPE(ToolTip)
QDBusArgument &operator<<(QDBusArgument &argument, const IconPixmap &icon);
const QDBusArgument &operator>>(const QDBusArgument &argument, IconPixmap &icon);
QDBusArgument &operator<<(QDBusArgument &argument, const ToolTip &toolTip);
const QDBusArgument &operator>>(const QDBusArgument &argument, ToolTip &toolTip);
#endif // DBUSTYPES_H

View File

@ -0,0 +1,69 @@
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
<interface name="org.kde.StatusNotifierItem">
<property name="Category" type="s" access="read"/>
<property name="Id" type="s" access="read"/>
<property name="Title" type="s" access="read"/>
<property name="Status" type="s" access="read"/>
<property name="WindowId" type="i" access="read"/>
<property name="IconThemePath" type="s" access="read"/>
<property name="Menu" type="o" access="read"/>
<property name="ItemIsMenu" type="b" access="read"/>
<property name="IconName" type="s" access="read"/>
<property name="IconPixmap" type="a(iiay)" access="read">
<annotation name="org.qtproject.QtDBus.QtTypeName" value="IconPixmapList"/>
</property>
<property name="OverlayIconName" type="s" access="read"/>
<property name="OverlayIconPixmap" type="a(iiay)" access="read">
<annotation name="org.qtproject.QtDBus.QtTypeName" value="IconPixmapList"/>
</property>
<property name="AttentionIconName" type="s" access="read"/>
<property name="AttentionIconPixmap" type="a(iiay)" access="read">
<annotation name="org.qtproject.QtDBus.QtTypeName" value="IconPixmapList"/>
</property>
<property name="AttentionMovieName" type="s" access="read"/>
<property name="ToolTip" type="(sa(iiay)ss)" access="read">
<annotation name="org.qtproject.QtDBus.QtTypeName" value="ToolTip"/>
</property>
<method name="ContextMenu">
<arg name="x" type="i" direction="in"/>
<arg name="y" type="i" direction="in"/>
</method>
<method name="Activate">
<arg name="x" type="i" direction="in"/>
<arg name="y" type="i" direction="in"/>
</method>
<method name="SecondaryActivate">
<arg name="x" type="i" direction="in"/>
<arg name="y" type="i" direction="in"/>
</method>
<method name="Scroll">
<arg name="delta" type="i" direction="in"/>
<arg name="orientation" type="s" direction="in"/>
</method>
<signal name="NewTitle">
</signal>
<signal name="NewIcon">
</signal>
<signal name="NewAttentionIcon">
</signal>
<signal name="NewOverlayIcon">
</signal>
<signal name="NewToolTip">
</signal>
<signal name="NewStatus">
<arg name="status" type="s"/>
</signal>
</interface>
</node>

View File

@ -0,0 +1,312 @@
/* BEGIN_COMMON_COPYRIGHT_HEADER
* (c)LGPL2+
*
* LXQt - a lightweight, Qt based, desktop toolset
* http://lxqt.org/
*
* Copyright: 2015 LXQt team
* Authors:
* Paulo Lieuthier <paulolieuthier@gmail.com>
*
* 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 "statusnotifieritem.h"
#include "statusnotifieritemadaptor.h"
#include <QDBusInterface>
#include <QDBusServiceWatcher>
#include <dbusmenu-qt5/dbusmenuexporter.h>
int StatusNotifierItem::mServiceCounter = 0;
StatusNotifierItem::StatusNotifierItem(QString id, QObject *parent)
: QObject(parent),
mAdaptor(new StatusNotifierItemAdaptor(this)),
mService(QString("org.freedesktop.StatusNotifierItem-%1-%2")
.arg(QCoreApplication::applicationPid())
.arg(++mServiceCounter)),
mId(id),
mTitle("Test"),
mStatus("Active"),
mMenu(nullptr),
mMenuExporter(nullptr)
{
// register service
QDBusConnection::sessionBus().registerService(mService);
QDBusConnection::sessionBus().registerObject("/StatusNotifierItem", this);
registerToHost();
// monitor the watcher service in case the host restarts
QDBusServiceWatcher *watcher = new QDBusServiceWatcher("org.kde.StatusNotifierWatcher",
QDBusConnection::sessionBus(),
QDBusServiceWatcher::WatchForOwnerChange,
this);
connect(watcher, &QDBusServiceWatcher::serviceOwnerChanged,
this, &StatusNotifierItem::onServiceOwnerChanged);
}
StatusNotifierItem::~StatusNotifierItem()
{
QDBusConnection::sessionBus().unregisterObject("/StatusNotifierItem");
QDBusConnection::sessionBus().unregisterService(mService);
QDBusConnection::sessionBus().disconnectFromBus(mService);
}
void StatusNotifierItem::registerToHost()
{
QDBusInterface interface("org.kde.StatusNotifierWatcher",
"/StatusNotifierWatcher",
"org.kde.StatusNotifierWatcher",
QDBusConnection::sessionBus());
interface.asyncCall("RegisterStatusNotifierItem", mService);
}
void StatusNotifierItem::onServiceOwnerChanged(const QString& service, const QString& oldOwner,
const QString& newOwner)
{
if (!newOwner.isEmpty())
registerToHost();
}
void StatusNotifierItem::onMenuDestroyed()
{
mMenu = nullptr;
mMenuExporter = nullptr; //mMenu is a QObject parent of the mMenuExporter
}
void StatusNotifierItem::setTitle(const QString &title)
{
if (mTitle == title)
return;
mTitle = title;
emit mAdaptor->NewTitle();
}
void StatusNotifierItem::setStatus(const QString &status)
{
if (mStatus == status)
return;
mStatus = status;
emit mAdaptor->NewStatus(mStatus);
}
void StatusNotifierItem::setMenuPath(const QString& path)
{
mMenuPath.setPath(path);
}
void StatusNotifierItem::setIconByName(const QString &name)
{
if (mIconName == name)
return;
mIconName = name;
emit mAdaptor->NewIcon();
}
void StatusNotifierItem::setIconByPixmap(const QIcon &icon)
{
if (mIconCacheKey == icon.cacheKey())
return;
mIconCacheKey = icon.cacheKey();
mIcon = iconToPixmapList(icon);
mIconName.clear();
emit mAdaptor->NewIcon();
}
void StatusNotifierItem::setOverlayIconByName(const QString &name)
{
if (mOverlayIconName == name)
return;
mOverlayIconName = name;
emit mAdaptor->NewOverlayIcon();
}
void StatusNotifierItem::setOverlayIconByPixmap(const QIcon &icon)
{
if (mOverlayIconCacheKey == icon.cacheKey())
return;
mOverlayIconCacheKey = icon.cacheKey();
mOverlayIcon = iconToPixmapList(icon);
mOverlayIconName.clear();
emit mAdaptor->NewOverlayIcon();
}
void StatusNotifierItem::setAttentionIconByName(const QString &name)
{
if (mAttentionIconName == name)
return;
mAttentionIconName = name;
emit mAdaptor->NewAttentionIcon();
}
void StatusNotifierItem::setAttentionIconByPixmap(const QIcon &icon)
{
if (mAttentionIconCacheKey == icon.cacheKey())
return;
mAttentionIconCacheKey = icon.cacheKey();
mAttentionIcon = iconToPixmapList(icon);
mAttentionIconName.clear();
emit mAdaptor->NewAttentionIcon();
}
void StatusNotifierItem::setToolTipTitle(const QString &title)
{
if (mTooltipTitle == title)
return;
mTooltipTitle = title;
emit mAdaptor->NewToolTip();
}
void StatusNotifierItem::setToolTipSubTitle(const QString &subTitle)
{
if (mTooltipSubtitle == subTitle)
return;
mTooltipSubtitle = subTitle;
emit mAdaptor->NewToolTip();
}
void StatusNotifierItem::setToolTipIconByName(const QString &name)
{
if (mTooltipIconName == name)
return;
mTooltipIconName = name;
emit mAdaptor->NewToolTip();
}
void StatusNotifierItem::setToolTipIconByPixmap(const QIcon &icon)
{
if (mTooltipIconCacheKey == icon.cacheKey())
return;
mTooltipIconCacheKey = icon.cacheKey();
mTooltipIcon = iconToPixmapList(icon);
mTooltipIconName.clear();
emit mAdaptor->NewToolTip();
}
void StatusNotifierItem::setContextMenu(QMenu* menu)
{
if (mMenu == menu)
return;
if (nullptr != mMenu)
{
disconnect(mMenu, &QObject::destroyed, this, &StatusNotifierItem::onMenuDestroyed);
}
mMenu = menu;
setMenuPath("/MenuBar");
//Note: we need to destroy menu exporter before creating new one -> to free the DBus object path for new menu
delete mMenuExporter;
if (nullptr != mMenu)
{
connect(mMenu, &QObject::destroyed, this, &StatusNotifierItem::onMenuDestroyed);
mMenuExporter = new DBusMenuExporter{this->menu().path(), mMenu};
}
}
void StatusNotifierItem::Activate(int x, int y)
{
if (mStatus == "NeedsAttention")
mStatus = "Active";
emit activateRequested(QPoint(x, y));
}
void StatusNotifierItem::SecondaryActivate(int x, int y)
{
if (mStatus == "NeedsAttention")
mStatus = "Active";
emit secondaryActivateRequested(QPoint(x, y));
}
void StatusNotifierItem::ContextMenu(int x, int y)
{
if (mMenu)
{
if (mMenu->isVisible())
mMenu->popup(QPoint(x, y));
else
mMenu->hide();
}
}
void StatusNotifierItem::Scroll(int delta, const QString &orientation)
{
Qt::Orientation orient = Qt::Vertical;
if (orientation.toLower() == "horizontal")
orient = Qt::Horizontal;
emit scrollRequested(delta, orient);
}
void StatusNotifierItem::showMessage(const QString& title, const QString& msg,
const QString& iconName, int secs)
{
QDBusInterface interface("org.freedesktop.Notifications", "/org/freedesktop/Notifications",
"org.freedesktop.Notifications", QDBusConnection::sessionBus());
interface.call("Notify", mTitle, (uint) 0, iconName, title,
msg, QStringList(), QVariantMap(), secs);
}
IconPixmapList StatusNotifierItem::iconToPixmapList(const QIcon& icon)
{
IconPixmapList pixmapList;
// long live KDE!
for (const QSize &size : icon.availableSizes())
{
QImage image = icon.pixmap(size).toImage();
IconPixmap pix;
pix.height = image.height();
pix.width = image.width();
if (image.format() != QImage::Format_ARGB32)
image = image.convertToFormat(QImage::Format_ARGB32);
pix.bytes = QByteArray((char *) image.bits(), image.byteCount());
// swap to network byte order if we are little endian
if (QSysInfo::ByteOrder == QSysInfo::LittleEndian)
{
quint32 *uintBuf = (quint32 *) pix.bytes.data();
for (uint i = 0; i < pix.bytes.size() / sizeof(quint32); ++i)
{
*uintBuf = qToBigEndian(*uintBuf);
++uintBuf;
}
}
pixmapList.append(pix);
}
return pixmapList;
}

View File

@ -0,0 +1,183 @@
/* BEGIN_COMMON_COPYRIGHT_HEADER
* (c)LGPL2+
*
* LXQt - a lightweight, Qt based, desktop toolset
* http://lxqt.org/
*
* Copyright: 2015 LXQt team
* Authors:
* Paulo Lieuthier <paulolieuthier@gmail.com>
*
* 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 */
#ifndef STATUS_NOTIFIER_ITEM_H
#define STATUS_NOTIFIER_ITEM_H
#include <QObject>
#include <QIcon>
#include <QMenu>
#include "dbustypes.h"
class StatusNotifierItemAdaptor;
class DBusMenuExporter;
class StatusNotifierItem : public QObject
{
Q_OBJECT
Q_PROPERTY(QString Title READ title)
Q_PROPERTY(QString Id READ id)
Q_PROPERTY(QString Status READ status)
Q_PROPERTY(QDBusObjectPath Menu READ menu)
Q_PROPERTY(QString IconName READ iconName)
Q_PROPERTY(IconPixmapList IconPixmap READ iconPixmap)
Q_PROPERTY(QString OverlayIconName READ overlayIconName)
Q_PROPERTY(IconPixmapList OverlayIconPixmap READ overlayIconPixmap)
Q_PROPERTY(QString AttentionIconName READ attentionIconName)
Q_PROPERTY(IconPixmapList AttentionIconPixmap READ attentionIconPixmap)
Q_PROPERTY(ToolTip ToolTip READ toolTip)
public:
StatusNotifierItem(QString id, QObject *parent = nullptr);
~StatusNotifierItem();
QString id() const
{ return mId; }
QString title() const
{ return mTitle; }
void setTitle(const QString &title);
QString status() const
{ return mStatus; }
void setStatus(const QString &status);
QDBusObjectPath menu() const
{ return mMenuPath; }
void setMenuPath(const QString &path);
QString iconName() const
{ return mIconName; }
void setIconByName(const QString &name);
IconPixmapList iconPixmap() const
{ return mIcon; }
void setIconByPixmap(const QIcon &icon);
QString overlayIconName() const
{ return mOverlayIconName; }
void setOverlayIconByName(const QString &name);
IconPixmapList overlayIconPixmap() const
{ return mOverlayIcon; }
void setOverlayIconByPixmap(const QIcon &icon);
QString attentionIconName() const
{ return mAttentionIconName; }
void setAttentionIconByName(const QString &name);
IconPixmapList attentionIconPixmap() const
{ return mAttentionIcon; }
void setAttentionIconByPixmap(const QIcon &icon);
QString toolTipTitle() const
{ return mTooltipTitle; }
void setToolTipTitle(const QString &title);
QString toolTipSubTitle() const
{ return mTooltipSubtitle; }
void setToolTipSubTitle(const QString &subTitle);
QString toolTipIconName() const
{ return mTooltipIconName; }
void setToolTipIconByName(const QString &name);
IconPixmapList toolTipIconPixmap() const
{ return mTooltipIcon; }
void setToolTipIconByPixmap(const QIcon &icon);
ToolTip toolTip() const
{
ToolTip tt;
tt.title = mTooltipTitle;
tt.description = mTooltipSubtitle;
tt.iconName = mTooltipIconName;
tt.iconPixmap = mTooltipIcon;
return tt;
}
/*!
* \Note: we don't take ownership for the \param menu
*/
void setContextMenu(QMenu *menu);
public slots:
void Activate(int x, int y);
void SecondaryActivate(int x, int y);
void ContextMenu(int x, int y);
void Scroll(int delta, const QString &orientation);
void showMessage(const QString &title, const QString &msg, const QString &iconName, int secs);
private:
void registerToHost();
IconPixmapList iconToPixmapList(const QIcon &icon);
private slots:
void onServiceOwnerChanged(const QString &service, const QString &oldOwner,
const QString &newOwner);
void onMenuDestroyed();
signals:
void activateRequested(const QPoint &pos);
void secondaryActivateRequested(const QPoint &pos);
void scrollRequested(int delta, Qt::Orientation orientation);
private:
StatusNotifierItemAdaptor *mAdaptor;
QString mService;
QString mId;
QString mTitle;
QString mStatus;
// icons
QString mIconName, mOverlayIconName, mAttentionIconName;
IconPixmapList mIcon, mOverlayIcon, mAttentionIcon;
qint64 mIconCacheKey, mOverlayIconCacheKey, mAttentionIconCacheKey;
// tooltip
QString mTooltipTitle, mTooltipSubtitle, mTooltipIconName;
IconPixmapList mTooltipIcon;
qint64 mTooltipIconCacheKey;
// menu
QMenu *mMenu;
QDBusObjectPath mMenuPath;
DBusMenuExporter *mMenuExporter;
static int mServiceCounter;
};
#endif