2014-11-13 19:30:51 +02:00
|
|
|
/***************************************************************************
|
|
|
|
* *
|
|
|
|
* Copyright (C) 2009 Marco Martin <notmart@gmail.com> *
|
|
|
|
* *
|
|
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
|
|
* it under the terms of the GNU General Public License as published by *
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
|
|
* (at your option) any later version. *
|
|
|
|
* *
|
|
|
|
* This program 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 General Public License for more details. *
|
|
|
|
* *
|
|
|
|
* You should have received a copy of the GNU General Public License *
|
|
|
|
* along with this program; if not, write to the *
|
|
|
|
* Free Software Foundation, Inc., *
|
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . *
|
|
|
|
***************************************************************************/
|
|
|
|
|
|
|
|
#include "dbussystemtraytask.h"
|
|
|
|
#include "dbussystemtrayprotocol.h"
|
|
|
|
|
2015-08-12 13:11:16 +03:00
|
|
|
#include <QtCore/qmetaobject.h>
|
2014-11-13 19:30:51 +02:00
|
|
|
#include <QtCore/QDir>
|
|
|
|
#include <QtCore/QCoreApplication>
|
|
|
|
#include <QtGui/QMenu>
|
|
|
|
#include <QtGui/QIcon>
|
|
|
|
|
2015-05-20 13:39:58 +00:00
|
|
|
#include <KJob>
|
|
|
|
#include <KIcon>
|
|
|
|
#include <KIconLoader>
|
|
|
|
#include <KStandardDirs>
|
|
|
|
#include <Plasma/ServiceJob>
|
|
|
|
#include <Plasma/ToolTipManager>
|
|
|
|
#include <Plasma/Applet>
|
|
|
|
#include <KDebug>
|
2014-11-13 19:30:51 +02:00
|
|
|
|
|
|
|
namespace SystemTray
|
|
|
|
{
|
|
|
|
|
|
|
|
DBusSystemTrayTask::DBusSystemTrayTask(const QString &serviceName, Plasma::DataEngine *dataEngine, QObject *parent)
|
|
|
|
: Task(parent),
|
|
|
|
m_serviceName(serviceName),
|
|
|
|
m_taskId(serviceName),
|
|
|
|
m_customIconLoader(0),
|
|
|
|
m_dataEngine(dataEngine),
|
|
|
|
m_service(dataEngine->serviceForSource(serviceName)),
|
|
|
|
m_isMenu(false),
|
|
|
|
m_valid(false)
|
|
|
|
{
|
|
|
|
kDebug();
|
|
|
|
m_service->setParent(this);
|
|
|
|
|
|
|
|
m_dataEngine->connectSource(serviceName, this);
|
|
|
|
}
|
|
|
|
|
|
|
|
DBusSystemTrayTask::~DBusSystemTrayTask()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
QGraphicsWidget* DBusSystemTrayTask::createWidget(Plasma::Applet */*host*/)
|
|
|
|
{
|
|
|
|
return 0; // d-bus tasks don't have widgets but provide info for GUI;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool DBusSystemTrayTask::isValid() const
|
|
|
|
{
|
|
|
|
return m_valid;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool DBusSystemTrayTask::isEmbeddable() const
|
|
|
|
{
|
|
|
|
return false; // this task cannot be embed because it only provides information to GUI part
|
|
|
|
}
|
|
|
|
|
|
|
|
bool DBusSystemTrayTask::isWidget() const
|
|
|
|
{
|
|
|
|
return false; // isn't a widget
|
|
|
|
}
|
|
|
|
|
|
|
|
void DBusSystemTrayTask::setShortcut(QString text) {
|
|
|
|
if (m_shortcut != text) {
|
|
|
|
m_shortcut = text;
|
|
|
|
emit changedShortcut();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
QString DBusSystemTrayTask::taskId() const
|
|
|
|
{
|
|
|
|
return m_taskId;
|
|
|
|
}
|
|
|
|
|
|
|
|
QIcon DBusSystemTrayTask::icon() const
|
|
|
|
{
|
|
|
|
return m_icon;
|
|
|
|
}
|
|
|
|
|
|
|
|
void DBusSystemTrayTask::activate1(int x, int y) const
|
|
|
|
{
|
|
|
|
KConfigGroup params;
|
|
|
|
if (m_isMenu) {
|
|
|
|
params = m_service->operationDescription("ContextMenu");
|
|
|
|
} else {
|
|
|
|
params = m_service->operationDescription("Activate");
|
|
|
|
}
|
|
|
|
params.writeEntry("x", x);
|
|
|
|
params.writeEntry("y", y);
|
|
|
|
KJob *job = m_service->startOperationCall(params);
|
|
|
|
connect(job, SIGNAL(result(KJob*)), this, SLOT(_onContextMenu(KJob*)));
|
|
|
|
}
|
|
|
|
|
|
|
|
void DBusSystemTrayTask::activate2(int x, int y) const
|
|
|
|
{
|
|
|
|
KConfigGroup params = m_service->operationDescription("SecondaryActivate");
|
|
|
|
params.writeEntry("x", x);
|
|
|
|
params.writeEntry("y", y);
|
|
|
|
m_service->startOperationCall(params);
|
|
|
|
}
|
|
|
|
|
|
|
|
void DBusSystemTrayTask::activateHorzScroll(int delta) const
|
|
|
|
{
|
|
|
|
_activateScroll(delta, "Horizontal");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Copied from kde-runtime/plasma/declarativeimports/core/iconitem.cpp
|
|
|
|
bool static hasm_svgIcon(QVariant source)
|
|
|
|
{
|
|
|
|
// Set up compat envrionment, afterwards it is 100% copy'n'pastable.
|
|
|
|
const QString element = source.toString();
|
|
|
|
const QString filename = element.split("-").first();
|
|
|
|
Plasma::Svg svgIcon;
|
|
|
|
Plasma::Svg *m_svgIcon = &svgIcon;
|
|
|
|
|
|
|
|
//try as a svg toolbar icon
|
|
|
|
m_svgIcon->setImagePath("toolbar-icons/" + filename);
|
|
|
|
|
|
|
|
//try as a svg normal icon (like systray)
|
|
|
|
if (!m_svgIcon->isValid() || !m_svgIcon->hasElement(element)) {
|
|
|
|
m_svgIcon->setImagePath("icons/" + filename);
|
|
|
|
}
|
|
|
|
m_svgIcon->setContainsMultipleImages(true);
|
|
|
|
|
|
|
|
//success?
|
|
|
|
if (m_svgIcon->isValid() && m_svgIcon->hasElement(element)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
QVariant DBusSystemTrayTask::customIcon(QVariant variant) const
|
|
|
|
{
|
|
|
|
if (variant.canConvert<QString>()) {
|
|
|
|
// If we have no icon loader there is nothing to be done with strings.
|
|
|
|
if (!m_customIconLoader)
|
|
|
|
return variant;
|
|
|
|
|
|
|
|
// If an SVG icon can be found (via Plasma theme) the name needs to be
|
|
|
|
// passed along for IconItem to be able to resolve to the theme name as
|
|
|
|
// well.
|
|
|
|
if (hasm_svgIcon(variant))
|
|
|
|
return variant;
|
|
|
|
|
|
|
|
// Otherwise return a QIcon from our custom icon loader.
|
|
|
|
return QVariant(KIcon(variant.toString(), m_customIconLoader));
|
|
|
|
} else {
|
|
|
|
// Most importantly QIcons. Nothing to do for those.
|
|
|
|
return variant;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void DBusSystemTrayTask::activateVertScroll(int delta) const
|
|
|
|
{
|
|
|
|
_activateScroll(delta, "Vertical");
|
|
|
|
}
|
|
|
|
|
|
|
|
void DBusSystemTrayTask::_activateScroll(int delta, QString direction) const
|
|
|
|
{
|
|
|
|
KConfigGroup params = m_service->operationDescription("Scroll");
|
|
|
|
params.writeEntry("delta", delta);
|
|
|
|
params.writeEntry("direction", direction);
|
|
|
|
m_service->startOperationCall(params);
|
|
|
|
}
|
|
|
|
|
|
|
|
void DBusSystemTrayTask::activateContextMenu(int x, int y) const
|
|
|
|
{
|
|
|
|
KConfigGroup params = m_service->operationDescription("ContextMenu");
|
|
|
|
params.writeEntry("x", x);
|
|
|
|
params.writeEntry("y", y);
|
|
|
|
KJob *job = m_service->startOperationCall(params);
|
|
|
|
connect(job, SIGNAL(result(KJob*)), this, SLOT(_onContextMenu(KJob*)));
|
|
|
|
}
|
|
|
|
|
|
|
|
void DBusSystemTrayTask::_onContextMenu(KJob *job)
|
|
|
|
{
|
|
|
|
if (QCoreApplication::closingDown()) {
|
|
|
|
// apparently an edge case can be triggered due to the async nature of all this
|
|
|
|
// see: https://bugs.kde.org/show_bug.cgi?id=251977
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Plasma::ServiceJob *sjob = qobject_cast<Plasma::ServiceJob *>(job);
|
|
|
|
if (!sjob) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
QMenu *menu = qobject_cast<QMenu *>(sjob->result().value<QObject *>());
|
|
|
|
if (menu) {
|
|
|
|
int x = sjob->parameters()["x"].toInt();
|
|
|
|
int y = sjob->parameters()["y"].toInt();
|
|
|
|
emit showContextMenu(x, y, QVariant::fromValue<QObject*>(menu));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void DBusSystemTrayTask::dataUpdated(const QString &taskName, const Plasma::DataEngine::Data &properties)
|
|
|
|
{
|
|
|
|
Q_UNUSED(taskName);
|
|
|
|
|
|
|
|
const QString id = properties["Id"].toString();
|
|
|
|
bool becomeValid = false;
|
|
|
|
if (!id.isEmpty() && id != m_taskId) {
|
|
|
|
m_taskId = id;
|
|
|
|
m_valid = true;
|
|
|
|
becomeValid = true;
|
|
|
|
setObjectName(QString("SystemTray-%1").arg(m_taskId));
|
|
|
|
}
|
|
|
|
|
|
|
|
QString cat = properties["Category"].toString();
|
|
|
|
if (!cat.isEmpty()) {
|
|
|
|
int index = metaObject()->indexOfEnumerator("Category");
|
|
|
|
int key = metaObject()->enumerator(index).keyToValue(cat.toLatin1());
|
|
|
|
|
|
|
|
if (key != -1) {
|
|
|
|
setCategory((Task::Category)key);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (properties["TitleChanged"].toBool() || becomeValid) {
|
|
|
|
QString title = properties["Title"].toString();
|
|
|
|
if (!title.isEmpty()) {
|
|
|
|
bool is_title_changed = (name() != title);
|
|
|
|
setName(title);
|
|
|
|
if (is_title_changed) {
|
|
|
|
emit changedTitle();
|
|
|
|
emit changed(this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (properties["IconsChanged"].toBool() || becomeValid) {
|
|
|
|
syncIcons(properties);
|
|
|
|
emit changedIcons();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (properties["StatusChanged"].toBool() || becomeValid) {
|
|
|
|
syncStatus(properties["Status"].toString());
|
|
|
|
}
|
|
|
|
|
|
|
|
if (properties["ToolTipChanged"].toBool() || becomeValid) {
|
|
|
|
syncToolTip(properties["ToolTipTitle"].toString(),
|
|
|
|
properties["ToolTipSubTitle"].toString(),
|
|
|
|
properties["ToolTipIcon"].value<QIcon>());
|
|
|
|
}
|
|
|
|
|
|
|
|
bool is_menu = properties["ItemIsMenu"].toBool();
|
|
|
|
if (is_menu != m_isMenu) {
|
|
|
|
m_isMenu = is_menu;
|
|
|
|
emit changedIsMenu();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (becomeValid) {
|
|
|
|
DBusSystemTrayProtocol *protocol = qobject_cast<DBusSystemTrayProtocol*>(parent());
|
|
|
|
if (protocol) {
|
|
|
|
protocol->initedTask(this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void DBusSystemTrayTask::syncIcons(const Plasma::DataEngine::Data &properties)
|
|
|
|
{
|
|
|
|
m_icon = properties["Icon"].value<QIcon>();
|
|
|
|
m_attentionIcon = properties["AttentionIcon"].value<QIcon>();
|
|
|
|
|
|
|
|
QString icon_name = properties["IconName"].toString();
|
|
|
|
QString att_icon_name = properties["AttentionIconName"].toString();
|
|
|
|
QString movie_path = properties["AttentionMovieName"].toString();
|
|
|
|
QString overlay_icon_name = properties["OverlayIconName"].value<QString>();
|
|
|
|
QString icon_theme_path = properties["IconThemePath"].value<QString>();
|
|
|
|
bool is_icon_name_changed = false;
|
|
|
|
bool is_att_icon_name_changed = false;
|
|
|
|
bool is_movie_path_changed = false;
|
|
|
|
bool is_overlay_icon_name_changed = false;
|
|
|
|
|
|
|
|
if (icon_name != m_iconName) {
|
|
|
|
m_iconName = icon_name;
|
|
|
|
is_icon_name_changed = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (att_icon_name != m_attentionIconName) {
|
|
|
|
m_attentionIconName = att_icon_name;
|
|
|
|
is_att_icon_name_changed = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!movie_path.isEmpty() && !QDir::isAbsolutePath(movie_path)) {
|
|
|
|
movie_path = KIconLoader::global()->moviePath(movie_path, KIconLoader::Panel);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (movie_path != m_moviePath) {
|
|
|
|
m_moviePath = movie_path;
|
|
|
|
is_movie_path_changed = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (overlay_icon_name != m_overlayIconName) {
|
|
|
|
m_overlayIconName = overlay_icon_name;
|
|
|
|
is_overlay_icon_name_changed = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (icon_theme_path != m_iconThemePath) {
|
|
|
|
m_iconThemePath = icon_theme_path;
|
|
|
|
|
|
|
|
if (m_customIconLoader) {
|
|
|
|
delete m_customIconLoader;
|
|
|
|
m_customIconLoader = 0;
|
|
|
|
}
|
|
|
|
const QString path = m_iconThemePath;
|
|
|
|
if (!path.isEmpty()) {
|
|
|
|
// FIXME: If last part of path is not "icons", this won't work!
|
|
|
|
QStringList tokens = path.split('/', QString::SkipEmptyParts);
|
|
|
|
if (tokens.length() >= 3 && tokens.takeLast() == QLatin1String("icons")) {
|
|
|
|
QString appName = tokens.takeLast();
|
2016-10-29 18:03:12 +00:00
|
|
|
QString prefix = QChar('/') + tokens.join("/");
|
2014-11-13 19:30:51 +02:00
|
|
|
// FIXME: Fix KIconLoader and KIconTheme so that we can use
|
|
|
|
// our own instance of KStandardDirs
|
|
|
|
KGlobal::dirs()->addResourceDir("data", prefix);
|
|
|
|
// We use a separate instance of KIconLoader to avoid
|
|
|
|
// adding all application dirs to KIconLoader::global(), to
|
|
|
|
// avoid potential icon name clashes between application
|
|
|
|
// icons
|
|
|
|
m_customIconLoader = new KIconLoader(appName, 0 /* dirs */, this);
|
|
|
|
} else {
|
|
|
|
kWarning() << "Wrong IconThemePath" << path << ": too short or does not end with 'icons'";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Trigger updates
|
|
|
|
is_icon_name_changed = true;
|
|
|
|
is_att_icon_name_changed = true;
|
|
|
|
is_overlay_icon_name_changed = true;
|
|
|
|
emit changedIcons();
|
|
|
|
}
|
|
|
|
|
|
|
|
// emit signals
|
|
|
|
if (is_icon_name_changed) {
|
|
|
|
emit changedIconName();
|
|
|
|
}
|
|
|
|
if (is_att_icon_name_changed) {
|
|
|
|
emit changedAttIconName();
|
|
|
|
}
|
|
|
|
if (is_movie_path_changed) {
|
|
|
|
emit changedMoviePath();
|
|
|
|
}
|
|
|
|
if (is_overlay_icon_name_changed) {
|
|
|
|
emit changedOverlayIconName();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//toolTip
|
|
|
|
|
|
|
|
void DBusSystemTrayTask::syncToolTip(const QString &title, const QString &subTitle, const QIcon &toolTipIcon)
|
|
|
|
{
|
|
|
|
if (title != m_tooltipTitle) {
|
|
|
|
m_tooltipTitle = title;
|
|
|
|
emit changedTooltipTitle();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (subTitle != m_tooltipText) {
|
|
|
|
m_tooltipText = subTitle;
|
|
|
|
emit changedTooltipText();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool is_icon_name_changed = (m_tooltipIcon.name() != toolTipIcon.name());
|
|
|
|
|
|
|
|
m_tooltipIcon = toolTipIcon;
|
|
|
|
emit changedTooltip();
|
|
|
|
|
|
|
|
if (is_icon_name_changed) {
|
|
|
|
emit changedTooltipIconName();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//Status
|
|
|
|
|
|
|
|
void DBusSystemTrayTask::syncStatus(QString newStatus)
|
|
|
|
{
|
|
|
|
Task::Status status = (Task::Status)metaObject()->enumerator(metaObject()->indexOfEnumerator("Status")).keyToValue(newStatus.toLatin1());
|
|
|
|
|
|
|
|
if (this->status() == status) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
setStatus(status);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2015-02-27 09:28:46 +00:00
|
|
|
#include "moc_dbussystemtraytask.cpp"
|