diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2fff7db76..d09ee318c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -30,19 +30,12 @@ if(WIN32)
else(WIN32)
pkg_check_modules(TAGLIB taglib)
pkg_check_modules(XINE libxine)
- pkg_check_modules(LIBNOTIFY libnotify)
endif(WIN32)
if (NOT Boost_FOUND)
message(FATAL_ERROR "Boost not found")
endif (NOT Boost_FOUND)
-if (LIBNOTIFY_FOUND)
- add_definitions(-DHAVE_LIBNOTIFY)
- link_directories(${LIBNOTIFY_LIBRARY_DIRS})
- include_directories(${LIBNOTIFY_INCLUDE_DIRS})
-endif (LIBNOTIFY_FOUND)
-
if (TAGLIB_VERSION VERSION_LESS 1.6)
message(FATAL_ERROR "Taglib version 1.6 or greater is required")
endif (TAGLIB_VERSION VERSION_LESS 1.6)
diff --git a/data/org.freedesktop.Notifications.xml b/data/org.freedesktop.Notifications.xml
new file mode 100644
index 000000000..41f733009
--- /dev/null
+++ b/data/org.freedesktop.Notifications.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index bd075398f..2e79396a7 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -184,6 +184,7 @@ else(APPLE)
set(CLEMENTINE-SOURCES ${CLEMENTINE-SOURCES} osd_win.cpp)
else(WIN32)
set(CLEMENTINE-SOURCES ${CLEMENTINE-SOURCES} osd_x11.cpp)
+ # MPRIS
qt4_add_dbus_adaptor(MPRIS-PLAYER-SOURCES
../data/org.freedesktop.MediaPlayer.player.xml
player.h Player mpris_player MprisPlayer)
@@ -193,10 +194,16 @@ else(APPLE)
qt4_add_dbus_adaptor(MPRIS-TRACKLIST-SOURCES
../data/org.freedesktop.MediaPlayer.tracklist.xml
player.h Player mpris_tracklist MprisTrackList)
+
+ # org.freedesktop.Notifications
+ qt4_add_dbus_interface(NOTIFICATION-SOURCES
+ ../data/org.freedesktop.Notifications.xml
+ notification)
set(CLEMENTINE-SOURCES ${CLEMENTINE-SOURCES}
${MPRIS-PLAYER-SOURCES}
${MPRIS-ROOT-SOURCES}
${MPRIS-TRACKLIST-SOURCES}
+ ${NOTIFICATION-SOURCES}
mpris.cpp
)
set(CLEMENTINE-MOC-HEADERS ${CLEMENTINE-MOC-HEADERS} mpris.h)
@@ -231,7 +238,6 @@ target_link_libraries(clementine_lib
qxt
lastfm
${XINE_LIBRARIES}
- ${LIBNOTIFY_LIBRARIES}
${TAGLIB_LIBRARIES}
${QT_LIBRARIES}
)
diff --git a/src/main.cpp b/src/main.cpp
index a0acb64f1..c8b6511a0 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -37,6 +37,7 @@
# include
# include
# include "mpris.h"
+# include "osd.h"
#endif
// Load sqlite plugin on windows
@@ -100,6 +101,7 @@ int main(int argc, char *argv[]) {
#ifdef Q_WS_X11
qDBusRegisterMetaType();
qDBusRegisterMetaType();
+ qDBusRegisterMetaType();
QDBusConnection::sessionBus().registerService("org.mpris.clementine");
MPRIS mpris;
#endif
diff --git a/src/osd.h b/src/osd.h
index f16a339ec..f6b2decd0 100644
--- a/src/osd.h
+++ b/src/osd.h
@@ -25,10 +25,13 @@
#include "song.h"
#ifdef Q_WS_X11
-# ifndef _NOTIFY_NOTIFICATION_H_
- struct GdkPixbuf;
- struct NotifyNotification;
-# endif
+#include
+#include
+#include "notification.h"
+
+QDBusArgument& operator<< (QDBusArgument& arg, const QImage& image);
+const QDBusArgument& operator>> (const QDBusArgument& arg, QImage& image);
+
#endif
class OSD : public QObject {
@@ -79,15 +82,16 @@ class OSD : public QObject {
bool show_on_volume_change_;
bool show_art_;
-#ifdef Q_WS_X11
- NotifyNotification* notification_;
- GdkPixbuf* pixbuf_;
-#endif
-
#ifdef Q_OS_DARWIN
class GrowlNotificationWrapper;
GrowlNotificationWrapper* wrapper_;
#endif // Q_OS_DARWIN
+
+#ifdef Q_WS_X11
+ boost::scoped_ptr interface_;
+ private slots:
+ void CallFinished(QDBusPendingCallWatcher* watcher);
+#endif
};
#endif // OSD_H
diff --git a/src/osd_x11.cpp b/src/osd_x11.cpp
index d84123e55..19e1b7cb8 100644
--- a/src/osd_x11.cpp
+++ b/src/osd_x11.cpp
@@ -14,34 +14,55 @@
along with Clementine. If not, see .
*/
-// Libnotify headers need to go before Qt ones because they use "signals" as
-// a variable name
-#ifdef HAVE_LIBNOTIFY
-# include
-# include
-# include
-#endif // HAVE_LIBNOTIFY
-
#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() {
- notification_ = NULL;
- pixbuf_ = NULL;
-#ifdef HAVE_LIBNOTIFY
- notify_init(QCoreApplication::applicationName().toUtf8().constData());
-#endif
+ interface_.reset(new org::freedesktop::Notifications(
+ "org.freedesktop.Notifications",
+ "/org/freedesktop/Notifications",
+ QDBusConnection::sessionBus()));
+ if (!interface_->isValid()) {
+ qWarning() << "Error connecting to notifications service.";
+ }
}
bool OSD::SupportsNativeNotifications() {
-#ifdef HAVE_LIBNOTIFY
return true;
-#else
- return false;
-#endif
}
bool OSD::SupportsTrayPopups() {
@@ -50,50 +71,45 @@ bool OSD::SupportsTrayPopups() {
void OSD::ShowMessageNative(const QString& summary, const QString& message,
const QString& icon) {
-#ifdef HAVE_LIBNOTIFY
- if (summary.isNull())
- return;
-
- #define STR(x) (x.isNull() ? NULL : x.toUtf8().constData())
-
- notification_ = notify_notification_new(
- STR(summary), STR(Qt::escape(message)), STR(icon), NULL);
-
- #undef STR
-
- notify_notification_set_urgency(notification_, NOTIFY_URGENCY_LOW);
- notify_notification_set_timeout(notification_, timeout_);
-
- if (pixbuf_) {
- notify_notification_set_icon_from_pixbuf(notification_, pixbuf_);
- }
-
- GError* error = NULL;
- notify_notification_show(notification_, &error);
- if (error) {
- qDebug() << "Error from notify_notification_show:" << error->message;
- g_error_free(error);
- }
-
- pixbuf_ = NULL;
-#endif // HAVE_LIBNOTIFY
+ QDBusPendingReply reply = interface_->Notify(
+ QCoreApplication::applicationName(),
+ 0,
+ icon,
+ summary,
+ message,
+ QStringList(),
+ QVariantMap(),
+ timeout_);
+ QDBusPendingCallWatcher* watcher = new QDBusPendingCallWatcher(reply, this);
+ connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
+ SLOT(CallFinished(QDBusPendingCallWatcher*)));
}
void OSD::ShowMessageNative(const QString& summary, const QString& message,
const QImage& image) {
-#ifdef HAVE_LIBNOTIFY
- QImage happy_gdk_image = image.scaledToHeight(100, Qt::SmoothTransformation)
- .convertToFormat(QImage::Format_RGB888);
- pixbuf_ = gdk_pixbuf_new_from_data(
- happy_gdk_image.bits(),
- GDK_COLORSPACE_RGB,
- false, // has_alpha
- 8, // bits_per_sample
- happy_gdk_image.width(),
- happy_gdk_image.height(),
- happy_gdk_image.bytesPerLine(),
- NULL, NULL);
-
- ShowMessageNative(summary, message, QString());
-#endif // HAVE_LIBNOTIFY
+ QVariantMap hints;
+ if (!image.isNull()) {
+ hints["image_data"] = QVariant(image);
+ }
+ QDBusPendingReply reply = interface_->Notify(
+ QCoreApplication::applicationName(),
+ 0,
+ QString(),
+ summary,
+ message,
+ QStringList(),
+ hints,
+ timeout_);
+ 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();
+ }
}