Files
cantata/gui/trayitem.cpp
2018-01-08 23:01:25 +01:00

293 lines
9.1 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* Cantata
*
* Copyright (c) 2011-2018 Craig Drummond <craig.p.drummond@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; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "trayitem.h"
#include "config.h"
#ifdef QT_QTDBUS_FOUND
#include "dbus/notify.h"
#endif
#include "mainwindow.h"
#include "settings.h"
#include "support/action.h"
#include "widgets/icons.h"
#include "mpd-interface/song.h"
#include "stdactions.h"
#include "support/utils.h"
#include "currentcover.h"
#include <QWheelEvent>
#include <QMenu>
#ifdef Q_OS_MAC
#include "mac/macnotify.h"
#endif
#ifndef Q_OS_MAC
class VolumeSliderEventHandler : public QObject
{
public:
VolumeSliderEventHandler(QObject *p) : QObject(p) { }
protected:
bool eventFilter(QObject *obj, QEvent *event) override
{
if (QEvent::Wheel==event->type()) {
int numDegrees = static_cast<QWheelEvent *>(event)->delta() / 8;
int numSteps = numDegrees / 15;
if (numSteps > 0) {
for (int i = 0; i < numSteps; ++i) {
StdActions::self()->increaseVolumeAction->trigger();
}
} else {
for (int i = 0; i > numSteps; --i) {
StdActions::self()->decreaseVolumeAction->trigger();
}
}
return true;
}
return QObject::eventFilter(obj, event);
}
};
#endif
TrayItem::TrayItem(MainWindow *p)
: QObject(p)
#ifndef Q_OS_MAC
, mw(p)
, trayItem(nullptr)
, trayItemMenu(nullptr)
#ifdef QT_QTDBUS_FOUND
, notification(nullptr)
#endif
, connectionsAction(nullptr)
, outputsAction(nullptr)
#endif
{
}
void TrayItem::showMessage(const QString &title, const QString &text, const QImage &img)
{
#ifdef Q_OS_MAC
MacNotify::showMessage(title, text, img);
#elif defined QT_QTDBUS_FOUND
if (!notification) {
notification=new Notify(this);
}
notification->show(title, text, img);
#else
Q_UNUSED(img)
if (trayItem) {
trayItem->showMessage(title, text, QSystemTrayIcon::Information, 5000);
}
#endif
}
static Action * copyAction(Action *orig)
{
Action *newAction=new Action(orig->parent());
newAction->setText(Utils::strippedText(orig->text()));
newAction->setIcon(orig->icon());
QObject::connect(newAction, SIGNAL(triggered()), orig, SIGNAL(triggered()));
QObject::connect(newAction, SIGNAL(triggered(bool)), orig, SIGNAL(triggered(bool)));
return newAction;
}
void TrayItem::setup()
{
#ifndef Q_OS_MAC
if (!Settings::self()->useSystemTray() || !Utils::useSystemTray()) {
if (trayItem) {
trayItem->setVisible(false);
trayItem->deleteLater();
trayItem=nullptr;
trayItemMenu->deleteLater();
trayItemMenu=nullptr;
}
return;
}
if (trayItem) {
return;
}
#ifndef Q_OS_MAC
connectionsAction=new Action(Utils::strippedText(mw->connectionsAction->text()), this);
connectionsAction->setVisible(false);
outputsAction=new Action(Utils::strippedText(mw->outputsAction->text()), this);
outputsAction->setVisible(false);
updateConnections();
updateOutputs();
#endif
// What systems DONT have a system tray? Also, isSytemTrayAvailable is checked in config dialog, so
// useSystemTray should not be set if there is none.
// Checking here seems to cause the icon not to appear if Cantata is autostarted in Plasma5 - #759
//if (!QSystemTrayIcon::isSystemTrayAvailable()) {
// return;
//}
trayItem = new QSystemTrayIcon(this);
trayItem->installEventFilter(new VolumeSliderEventHandler(this));
trayItemMenu = new QMenu(nullptr);
trayItemMenu->addAction(StdActions::self()->prevTrackAction);
trayItemMenu->addAction(StdActions::self()->playPauseTrackAction);
trayItemMenu->addAction(StdActions::self()->stopPlaybackAction);
trayItemMenu->addAction(StdActions::self()->stopAfterCurrentTrackAction);
trayItemMenu->addAction(StdActions::self()->nextTrackAction);
#ifndef Q_OS_MAC
trayItemMenu->addSeparator();
trayItemMenu->addAction(connectionsAction);
trayItemMenu->addAction(outputsAction);
#endif
trayItemMenu->addSeparator();
trayItemMenu->addAction(mw->restoreAction);
trayItemMenu->addSeparator();
trayItemMenu->addAction(copyAction(mw->quitAction));
trayItem->setContextMenu(trayItemMenu);
QIcon icon=QIcon::fromTheme(QIcon::hasThemeIcon("cantata-panel") ? "cantata-panel" : "cantata");
#if !defined Q_OS_MAC && !defined Q_OS_WIN
// Bug: 660 If installed to non-standard folder, QIcon::fromTheme does not seem to find icon. Therefore
// add icon files here...
if (icon.isNull()) {
QStringList sizes=QStringList() << "16" << "22" << "24" << "32" << "48" << "64";
for (const QString &s: sizes) {
icon.addFile(QLatin1String(ICON_INSTALL_PREFIX "/")+s+QLatin1Char('x')+s+QLatin1String("/apps/cantata.png"));
}
icon.addFile(QLatin1String(ICON_INSTALL_PREFIX "/scalable/apps/cantata.svg"));
}
#endif
trayItem->setIcon(icon);
trayItem->setToolTip(tr("Cantata"));
trayItem->show();
connect(trayItem, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(trayItemClicked(QSystemTrayIcon::ActivationReason)));
#endif
}
void TrayItem::trayItemClicked(QSystemTrayIcon::ActivationReason reason)
{
#ifdef Q_OS_MAC
Q_UNUSED(reason)
#else
switch (reason) {
case QSystemTrayIcon::Trigger:
if (mw->isHidden()) {
mw->restoreWindow();
} else {
mw->hideWindow();
}
break;
case QSystemTrayIcon::MiddleClick:
mw->playPauseTrack();
break;
default:
break;
}
#endif
}
void TrayItem::songChanged(const Song &song, bool isPlaying)
{
#ifdef Q_OS_MAC
if (Settings::self()->showPopups()) {
bool useable=song.isStandardStream()
? !song.title.isEmpty() && !song.name().isEmpty()
: !song.title.isEmpty() && !song.artist.isEmpty() && !song.album.isEmpty();
if (useable) {
QString text=song.describe(false);
if (song.time>0) {
text+=QString(" ")+Utils::formatTime(song.time);
}
MacNotify::showMessage(tr("Now playing"), text, CurrentCover::self()->image());
}
}
#else
if (Settings::self()->showPopups() || trayItem) {
bool useable=song.isStandardStream()
? !song.title.isEmpty() && !song.name().isEmpty()
: !song.title.isEmpty() && !song.artist.isEmpty() && !song.album.isEmpty();
if (useable) {
QString text=song.describe(false);
if (song.time>0) {
text+=QString(" ")+Utils::formatTime(song.time);
}
if (trayItem) {
#if defined Q_OS_WIN || defined Q_OS_MAC || !defined QT_QTDBUS_FOUND
trayItem->setToolTip(tr("Cantata")+"\n\n"+text);
// The pure Qt implementation needs both the tray icon and the setting checked.
if (Settings::self()->showPopups() && isPlaying) {
trayItem->showMessage(tr("Now playing"), text, QSystemTrayIcon::Information, 5000);
}
#else
trayItem->setToolTip(tr("Cantata")+"\n\n"+text);
#endif
}
#ifdef QT_QTDBUS_FOUND
if (Settings::self()->showPopups() && isPlaying) {
if (!notification) {
notification=new Notify(this);
}
notification->show(tr("Now playing"), text, CurrentCover::self()->image());
}
#endif
} else if (trayItem) {
trayItem->setToolTip(tr("Cantata"));
}
}
#endif
}
#ifndef Q_OS_MAC
static void copyMenu(Action *from, Action *to)
{
if (!to) {
return;
}
to->setVisible(from->isVisible());
if (to->isVisible()) {
if (!to->menu()) {
to->setMenu(new QMenu(nullptr));
}
QMenu *m=to->menu();
m->clear();
for (QAction *act: from->menu()->actions()) {
m->addAction(act);
}
}
}
#endif
void TrayItem::updateConnections()
{
#ifndef Q_OS_MAC
copyMenu(mw->connectionsAction, connectionsAction);
#endif
}
void TrayItem::updateOutputs()
{
#ifndef Q_OS_MAC
copyMenu(mw->outputsAction, outputsAction);
#endif
}