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"