2010-03-24 00:11:46 +01:00
|
|
|
/* This file is part of Clementine.
|
2010-11-20 14:27:10 +01:00
|
|
|
Copyright 2010, David Sansome <me@davidsansome.com>
|
2010-03-24 00:11:46 +01:00
|
|
|
|
|
|
|
Clementine 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 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
Clementine 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 Clementine. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2010-01-08 15:52:05 +01:00
|
|
|
#include <QtDebug>
|
2020-09-18 16:15:19 +02:00
|
|
|
#include <memory>
|
2010-12-26 14:38:35 +01:00
|
|
|
|
2014-02-06 14:48:00 +01:00
|
|
|
#include "config.h"
|
|
|
|
#include "core/logging.h"
|
2020-09-18 16:15:19 +02:00
|
|
|
#include "osd.h"
|
2014-02-06 14:48:00 +01:00
|
|
|
|
2010-12-26 14:38:35 +01:00
|
|
|
#ifdef HAVE_DBUS
|
|
|
|
#include <QCoreApplication>
|
2010-01-08 20:50:29 +01:00
|
|
|
#include <QTextDocument>
|
2010-01-08 15:52:05 +01:00
|
|
|
|
2020-09-18 16:15:19 +02:00
|
|
|
#include "dbus/notification.h"
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
QDBusArgument& operator<<(QDBusArgument& arg, const QImage& image) {
|
2010-03-25 18:52:28 +01:00
|
|
|
if (image.isNull()) {
|
|
|
|
// Sometimes this gets called with a null QImage for no obvious reason.
|
|
|
|
arg.beginStructure();
|
|
|
|
arg << 0 << 0 << 0 << false << 0 << 0 << QByteArray();
|
|
|
|
arg.endStructure();
|
|
|
|
return arg;
|
|
|
|
}
|
|
|
|
QImage scaled = image.scaledToHeight(100, Qt::SmoothTransformation);
|
2011-05-14 15:43:33 +02:00
|
|
|
|
|
|
|
scaled = scaled.convertToFormat(QImage::Format_ARGB32);
|
|
|
|
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
|
|
|
|
// ABGR -> ARGB
|
|
|
|
QImage i = scaled.rgbSwapped();
|
|
|
|
#else
|
|
|
|
// ABGR -> GBAR
|
|
|
|
QImage i(scaled.size(), scaled.format());
|
|
|
|
for (int y = 0; y < i.height(); ++y) {
|
2014-02-07 16:34:20 +01:00
|
|
|
QRgb* p = (QRgb*)scaled.scanLine(y);
|
|
|
|
QRgb* q = (QRgb*)i.scanLine(y);
|
2011-05-14 15:43:33 +02:00
|
|
|
QRgb* end = p + scaled.width();
|
|
|
|
while (p < end) {
|
|
|
|
*q = qRgba(qGreen(*p), qBlue(*p), qAlpha(*p), qRed(*p));
|
|
|
|
p++;
|
|
|
|
q++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2010-03-25 18:52:28 +01:00
|
|
|
arg.beginStructure();
|
|
|
|
arg << i.width();
|
|
|
|
arg << i.height();
|
|
|
|
arg << i.bytesPerLine();
|
|
|
|
arg << i.hasAlphaChannel();
|
|
|
|
int channels = i.isGrayscale() ? 1 : (i.hasAlphaChannel() ? 4 : 3);
|
|
|
|
arg << i.depth() / channels;
|
|
|
|
arg << channels;
|
2020-01-05 19:31:40 +01:00
|
|
|
#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
|
|
|
|
arg << QByteArray(reinterpret_cast<const char*>(i.bits()), i.sizeInBytes());
|
|
|
|
#else
|
2015-04-15 18:26:09 +02:00
|
|
|
arg << QByteArray(reinterpret_cast<const char*>(i.bits()), i.byteCount());
|
2020-01-05 19:31:40 +01:00
|
|
|
#endif
|
2010-03-25 18:52:28 +01:00
|
|
|
arg.endStructure();
|
|
|
|
return arg;
|
|
|
|
}
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
const QDBusArgument& operator>>(const QDBusArgument& arg, QImage& image) {
|
2010-03-25 18:52:28 +01:00
|
|
|
// This is needed to link but shouldn't be called.
|
|
|
|
Q_ASSERT(0);
|
|
|
|
return arg;
|
|
|
|
}
|
2014-02-07 16:34:20 +01:00
|
|
|
#endif // HAVE_DBUS
|
2010-03-25 18:52:28 +01:00
|
|
|
|
2010-01-08 15:52:05 +01:00
|
|
|
void OSD::Init() {
|
2011-03-12 22:19:32 +01:00
|
|
|
#ifdef HAVE_DBUS
|
2011-01-08 17:06:28 +01:00
|
|
|
notification_id_ = 0;
|
|
|
|
|
2010-06-25 21:04:10 +02:00
|
|
|
interface_.reset(new OrgFreedesktopNotificationsInterface(
|
|
|
|
OrgFreedesktopNotificationsInterface::staticInterfaceName(),
|
2014-02-07 16:34:20 +01:00
|
|
|
"/org/freedesktop/Notifications", QDBusConnection::sessionBus()));
|
2010-03-25 18:52:28 +01:00
|
|
|
if (!interface_->isValid()) {
|
2011-04-22 18:50:29 +02:00
|
|
|
qLog(Warning) << "Error connecting to notifications service.";
|
2010-03-25 18:52:28 +01:00
|
|
|
}
|
2014-02-07 16:34:20 +01:00
|
|
|
#endif // HAVE_DBUS
|
2010-01-08 15:52:05 +01:00
|
|
|
}
|
|
|
|
|
2010-02-26 23:37:48 +01:00
|
|
|
bool OSD::SupportsNativeNotifications() {
|
2010-12-26 14:38:35 +01:00
|
|
|
#ifdef HAVE_DBUS
|
2010-02-26 23:37:48 +01:00
|
|
|
return true;
|
2010-12-26 14:38:35 +01:00
|
|
|
#else
|
|
|
|
return false;
|
|
|
|
#endif
|
2010-02-26 23:37:48 +01:00
|
|
|
}
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
bool OSD::SupportsTrayPopups() { return true; }
|
2010-02-03 18:21:25 +01:00
|
|
|
|
|
|
|
void OSD::ShowMessageNative(const QString& summary, const QString& message,
|
2010-03-30 02:08:16 +02:00
|
|
|
const QString& icon, const QImage& image) {
|
2010-12-26 14:38:35 +01:00
|
|
|
#ifdef HAVE_DBUS
|
2014-02-07 16:34:20 +01:00
|
|
|
if (!interface_) return;
|
2011-01-08 17:06:28 +01:00
|
|
|
|
2010-03-25 18:52:28 +01:00
|
|
|
QVariantMap hints;
|
|
|
|
if (!image.isNull()) {
|
|
|
|
hints["image_data"] = QVariant(image);
|
|
|
|
}
|
2010-03-30 02:08:16 +02:00
|
|
|
|
2019-06-16 19:03:47 +02:00
|
|
|
hints["desktop-entry"] = QVariant("clementine");
|
2017-07-06 19:39:07 +02:00
|
|
|
hints["transient"] = QVariant(true);
|
|
|
|
|
2010-03-30 02:08:16 +02:00
|
|
|
int id = 0;
|
2014-02-07 16:34:20 +01:00
|
|
|
if (last_notification_time_.secsTo(QDateTime::currentDateTime()) * 1000 <
|
|
|
|
timeout_msec_) {
|
2010-03-30 02:08:16 +02:00
|
|
|
// Reuse the existing popup if it's still open. The reason we don't always
|
|
|
|
// reuse the popup is because the notification daemon on KDE4 won't re-show
|
|
|
|
// the bubble if it's already gone to the tray. See issue #118
|
|
|
|
id = notification_id_;
|
|
|
|
}
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
QDBusPendingReply<uint> reply =
|
|
|
|
interface_->Notify(QCoreApplication::applicationName(), id, icon, summary,
|
|
|
|
message, QStringList(), hints, timeout_msec_);
|
2010-03-25 18:52:28 +01:00
|
|
|
QDBusPendingCallWatcher* watcher = new QDBusPendingCallWatcher(reply, this);
|
|
|
|
connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
|
2014-02-07 16:34:20 +01:00
|
|
|
SLOT(CallFinished(QDBusPendingCallWatcher*)));
|
|
|
|
#else // HAVE_DBUS
|
2011-04-22 18:50:29 +02:00
|
|
|
qLog(Warning) << "not implemented";
|
2014-02-07 16:34:20 +01:00
|
|
|
#endif // HAVE_DBUS
|
2010-03-25 18:52:28 +01:00
|
|
|
}
|
2010-02-24 23:38:35 +01:00
|
|
|
|
2010-12-26 14:38:35 +01:00
|
|
|
#ifdef HAVE_DBUS
|
2010-03-25 18:52:28 +01:00
|
|
|
void OSD::CallFinished(QDBusPendingCallWatcher* watcher) {
|
2014-02-06 14:48:00 +01:00
|
|
|
std::unique_ptr<QDBusPendingCallWatcher> w(watcher);
|
2010-03-25 18:52:28 +01:00
|
|
|
|
|
|
|
QDBusPendingReply<uint> reply = *watcher;
|
|
|
|
if (reply.isError()) {
|
2011-04-22 18:50:29 +02:00
|
|
|
qLog(Warning) << "Error sending notification" << reply.error().name();
|
2010-03-29 22:08:32 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint id = reply.value();
|
|
|
|
if (id != 0) {
|
|
|
|
notification_id_ = id;
|
2010-03-30 02:08:16 +02:00
|
|
|
last_notification_time_ = QDateTime::currentDateTime();
|
2010-03-25 18:52:28 +01:00
|
|
|
}
|
2010-02-24 22:44:14 +01:00
|
|
|
}
|
2010-12-26 14:38:35 +01:00
|
|
|
#endif
|