File indexing completed on 2024-04-21 03:56:29

0001 /*
0002     This file is part of the KDE libraries
0003     SPDX-FileCopyrightText: 2005-2007 Olivier Goffart <ogoffart at kde.org>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-only
0006 */
0007 
0008 #include "knotifyconfigactionswidget.h"
0009 
0010 #include "knotifyconfigelement.h"
0011 #include <knotifyconfig_debug.h>
0012 
0013 #include <QFile>
0014 #include <QStandardPaths>
0015 #include <QUrl>
0016 
0017 #if HAVE_CANBERRA
0018 #include <canberra.h>
0019 #elif HAVE_PHONON
0020 #include <phonon/mediaobject.h>
0021 #endif
0022 
0023 KNotifyConfigActionsWidget::KNotifyConfigActionsWidget(QWidget *parent)
0024     : QWidget(parent)
0025 {
0026     m_ui.setupUi(this);
0027 
0028     // Show sounds directory by default
0029     QStringList soundDirs = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("sounds"), QStandardPaths::LocateDirectory);
0030     if (!soundDirs.isEmpty()) {
0031         m_ui.Sound_select->setStartDir(QUrl::fromLocalFile(soundDirs.last()));
0032     }
0033     m_ui.Sound_select->setMimeTypeFilters({QStringLiteral("audio/x-vorbis+ogg"), QStringLiteral("audio/x-wav")});
0034 
0035     m_ui.Sound_play->setIcon(QIcon::fromTheme(QStringLiteral("media-playback-start")));
0036     m_ui.Sound_check->setIcon(QIcon::fromTheme(QStringLiteral("media-playback-start")));
0037     m_ui.Popup_check->setIcon(QIcon::fromTheme(QStringLiteral("dialog-information")));
0038 
0039     connect(m_ui.Sound_check, SIGNAL(toggled(bool)), this, SIGNAL(changed()));
0040     connect(m_ui.Popup_check, SIGNAL(toggled(bool)), this, SIGNAL(changed()));
0041     connect(m_ui.Sound_select, SIGNAL(textChanged(QString)), this, SIGNAL(changed()));
0042     connect(m_ui.Sound_play, SIGNAL(clicked()), this, SLOT(slotPlay()));
0043 }
0044 
0045 KNotifyConfigActionsWidget::~KNotifyConfigActionsWidget()
0046 {
0047 #if HAVE_CANBERRA
0048     if (m_context) {
0049         ca_context_destroy(m_context);
0050     }
0051     m_context = nullptr;
0052 #endif
0053 }
0054 
0055 void KNotifyConfigActionsWidget::setConfigElement(KNotifyConfigElement *config)
0056 {
0057     bool blocked = blockSignals(true); // to block the changed() signal
0058     QString prstring = config->readEntry(QStringLiteral("Action"));
0059     QStringList actions = prstring.split(QLatin1Char('|'));
0060 
0061     m_ui.Sound_check->setChecked(actions.contains(QStringLiteral("Sound")));
0062     m_ui.Popup_check->setChecked(actions.contains(QStringLiteral("Popup")));
0063 
0064     m_ui.Sound_select->setUrl(QUrl(config->readEntry(QStringLiteral("Sound"), true)));
0065 
0066     blockSignals(blocked);
0067 }
0068 
0069 void KNotifyConfigActionsWidget::save(KNotifyConfigElement *config)
0070 {
0071     QStringList actions;
0072     if (m_ui.Sound_check->isChecked()) {
0073         actions << QStringLiteral("Sound");
0074     }
0075     if (m_ui.Popup_check->isChecked()) {
0076         actions << QStringLiteral("Popup");
0077     }
0078 
0079     config->writeEntry(QStringLiteral("Action"), actions.join(QLatin1Char('|')));
0080 
0081     config->writeEntry(QStringLiteral("Sound"),
0082                        m_ui.Sound_select->text()); // don't use .url() here, .notifyrc files have predefined "static" entries with no path
0083 }
0084 
0085 void KNotifyConfigActionsWidget::slotPlay()
0086 {
0087     const QString soundFilename = m_ui.Sound_select->text();
0088     QUrl soundURL;
0089     const auto dataLocations = QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation);
0090     for (const QString &dataLocation : dataLocations) {
0091         soundURL = QUrl::fromUserInput(soundFilename, dataLocation + QStringLiteral("/sounds"), QUrl::AssumeLocalFile);
0092         if (soundURL.isLocalFile() && QFile::exists(soundURL.toLocalFile())) {
0093             break;
0094         } else if (!soundURL.isLocalFile() && soundURL.isValid()) {
0095             break;
0096         }
0097         soundURL.clear();
0098     }
0099 
0100 #if HAVE_CANBERRA
0101     if (!m_context) {
0102         int ret = ca_context_create(&m_context);
0103         if (ret != CA_SUCCESS) {
0104             qCWarning(KNOTIFYCONFIG_LOG) << "Failed to initialize canberra context for audio notification:" << ca_strerror(ret);
0105             m_context = nullptr;
0106             return;
0107         }
0108 
0109         QString desktopFileName = QGuiApplication::desktopFileName();
0110         // handle apps which set the desktopFileName property with filename suffix,
0111         // due to unclear API dox (https://bugreports.qt.io/browse/QTBUG-75521)
0112         if (desktopFileName.endsWith(QLatin1String(".desktop"))) {
0113             desktopFileName.chop(8);
0114         }
0115         ret = ca_context_change_props(m_context,
0116                                       CA_PROP_APPLICATION_NAME,
0117                                       qUtf8Printable(qApp->applicationDisplayName()),
0118                                       CA_PROP_APPLICATION_ID,
0119                                       qUtf8Printable(desktopFileName),
0120                                       CA_PROP_APPLICATION_ICON_NAME,
0121                                       qUtf8Printable(qApp->windowIcon().name()),
0122                                       nullptr);
0123         if (ret != CA_SUCCESS) {
0124             qCWarning(KNOTIFYCONFIG_LOG) << "Failed to set application properties on canberra context for audio notification:" << ca_strerror(ret);
0125         }
0126     }
0127 
0128     ca_proplist *props = nullptr;
0129     ca_proplist_create(&props);
0130 
0131     // We'll also want this cached for a time. volatile makes sure the cache is
0132     // dropped after some time or when the cache is under pressure.
0133     ca_proplist_sets(props, CA_PROP_MEDIA_FILENAME, QFile::encodeName(soundURL.toLocalFile()).constData());
0134     ca_proplist_sets(props, CA_PROP_CANBERRA_CACHE_CONTROL, "volatile");
0135 
0136     int ret = ca_context_play_full(m_context, 0, props, nullptr, nullptr);
0137 
0138     ca_proplist_destroy(props);
0139 
0140     if (ret != CA_SUCCESS) {
0141         qCWarning(KNOTIFYCONFIG_LOG) << "Failed to play sound with canberra:" << ca_strerror(ret);
0142         return;
0143     }
0144 #elif HAVE_PHONON
0145     Phonon::MediaObject *media = Phonon::createPlayer(Phonon::NotificationCategory, soundURL);
0146     media->play();
0147     connect(media, SIGNAL(finished()), media, SLOT(deleteLater()));
0148 #endif
0149 }
0150 
0151 #include "moc_knotifyconfigactionswidget.cpp"