/* This file is part of Clementine. 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 . */ #include "osd.h" #include #include #include using boost::scoped_ptr; QDBusArgument& operator<< (QDBusArgument& arg, const QImage& image) { 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); QImage i = scaled.convertToFormat(QImage::Format_ARGB32).rgbSwapped(); 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; arg << QByteArray(reinterpret_cast(i.bits()), i.numBytes()); arg.endStructure(); return arg; } const QDBusArgument& operator>> (const QDBusArgument& arg, QImage& image) { // This is needed to link but shouldn't be called. Q_ASSERT(0); return arg; } void OSD::Init() { interface_.reset(new org::freedesktop::Notifications( "org.freedesktop.Notifications", "/org/freedesktop/Notifications", QDBusConnection::sessionBus())); if (!interface_->isValid()) { qWarning() << "Error connecting to notifications service."; } notification_id_ = 0; } bool OSD::SupportsNativeNotifications() { return true; } bool OSD::SupportsTrayPopups() { return true; } void OSD::ShowMessageNative(const QString& summary, const QString& message, const QString& icon, const QImage& image) { QVariantMap hints; if (!image.isNull()) { hints["image_data"] = QVariant(image); } int id = 0; if (last_notification_time_.secsTo(QDateTime::currentDateTime()) * 1000 < timeout_msec_) { // 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_; } QDBusPendingReply reply = interface_->Notify( QCoreApplication::applicationName(), id, icon, summary, message, QStringList(), hints, timeout_msec_); QDBusPendingCallWatcher* watcher = new QDBusPendingCallWatcher(reply, this); connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), SLOT(CallFinished(QDBusPendingCallWatcher*))); } void OSD::CallFinished(QDBusPendingCallWatcher* watcher) { scoped_ptr w(watcher); QDBusPendingReply reply = *watcher; if (reply.isError()) { qWarning() << "Error sending notification" << reply.error().name(); return; } uint id = reply.value(); if (id != 0) { notification_id_ = id; last_notification_time_ = QDateTime::currentDateTime(); } }