1 | /* |
2 | This file is part of the KDE libraries |
3 | SPDX-FileCopyrightText: 2005-2007 Olivier Goffart <ogoffart at kde.org> |
4 | |
5 | SPDX-License-Identifier: LGPL-2.0-only |
6 | */ |
7 | |
8 | #include "knotifyconfigactionswidget.h" |
9 | |
10 | #include "knotifyconfigelement.h" |
11 | #include <knotifyconfig_debug.h> |
12 | |
13 | #include <QFile> |
14 | #include <QStandardPaths> |
15 | #include <QUrl> |
16 | |
17 | #if HAVE_CANBERRA |
18 | #include <canberra.h> |
19 | #elif HAVE_PHONON |
20 | #include <phonon/mediaobject.h> |
21 | #endif |
22 | |
23 | KNotifyConfigActionsWidget::KNotifyConfigActionsWidget(QWidget *parent) |
24 | : QWidget(parent) |
25 | { |
26 | m_ui.setupUi(this); |
27 | |
28 | // Show sounds directory by default |
29 | QStringList soundDirs = QStandardPaths::locateAll(type: QStandardPaths::GenericDataLocation, QStringLiteral("sounds" ), options: QStandardPaths::LocateDirectory); |
30 | if (!soundDirs.isEmpty()) { |
31 | m_ui.Sound_select->setStartDir(QUrl::fromLocalFile(localfile: soundDirs.last())); |
32 | } |
33 | m_ui.Sound_select->setMimeTypeFilters({QStringLiteral("audio/x-vorbis+ogg" ), QStringLiteral("audio/x-wav" )}); |
34 | |
35 | m_ui.Sound_play->setIcon(QIcon::fromTheme(QStringLiteral("media-playback-start" ))); |
36 | m_ui.Sound_check->setIcon(QIcon::fromTheme(QStringLiteral("media-playback-start" ))); |
37 | m_ui.Popup_check->setIcon(QIcon::fromTheme(QStringLiteral("dialog-information" ))); |
38 | |
39 | connect(sender: m_ui.Sound_check, SIGNAL(toggled(bool)), receiver: this, SIGNAL(changed())); |
40 | connect(sender: m_ui.Popup_check, SIGNAL(toggled(bool)), receiver: this, SIGNAL(changed())); |
41 | connect(sender: m_ui.Sound_select, SIGNAL(textChanged(QString)), receiver: this, SIGNAL(changed())); |
42 | connect(sender: m_ui.Sound_play, SIGNAL(clicked()), receiver: this, SLOT(slotPlay())); |
43 | } |
44 | |
45 | KNotifyConfigActionsWidget::~KNotifyConfigActionsWidget() |
46 | { |
47 | #if HAVE_CANBERRA |
48 | if (m_context) { |
49 | ca_context_destroy(c: m_context); |
50 | } |
51 | m_context = nullptr; |
52 | #endif |
53 | } |
54 | |
55 | void KNotifyConfigActionsWidget::setConfigElement(KNotifyConfigElement *config) |
56 | { |
57 | bool blocked = blockSignals(b: true); // to block the changed() signal |
58 | QString prstring = config->readEntry(QStringLiteral("Action" )); |
59 | QStringList actions = prstring.split(sep: QLatin1Char('|')); |
60 | |
61 | m_ui.Sound_check->setChecked(actions.contains(QStringLiteral("Sound" ))); |
62 | m_ui.Popup_check->setChecked(actions.contains(QStringLiteral("Popup" ))); |
63 | |
64 | m_ui.Sound_select->setUrl(QUrl(config->readEntry(QStringLiteral("Sound" ), path: true))); |
65 | |
66 | blockSignals(b: blocked); |
67 | } |
68 | |
69 | void KNotifyConfigActionsWidget::save(KNotifyConfigElement *config) |
70 | { |
71 | QStringList actions; |
72 | if (m_ui.Sound_check->isChecked()) { |
73 | actions << QStringLiteral("Sound" ); |
74 | } |
75 | if (m_ui.Popup_check->isChecked()) { |
76 | actions << QStringLiteral("Popup" ); |
77 | } |
78 | |
79 | config->writeEntry(QStringLiteral("Action" ), data: actions.join(sep: QLatin1Char('|'))); |
80 | |
81 | config->writeEntry(QStringLiteral("Sound" ), |
82 | data: m_ui.Sound_select->text()); // don't use .url() here, .notifyrc files have predefined "static" entries with no path |
83 | } |
84 | |
85 | void KNotifyConfigActionsWidget::slotPlay() |
86 | { |
87 | const QString soundFilename = m_ui.Sound_select->text(); |
88 | QUrl soundURL; |
89 | const auto dataLocations = QStandardPaths::standardLocations(type: QStandardPaths::GenericDataLocation); |
90 | for (const QString &dataLocation : dataLocations) { |
91 | soundURL = QUrl::fromUserInput(userInput: soundFilename, workingDirectory: dataLocation + QStringLiteral("/sounds" ), options: QUrl::AssumeLocalFile); |
92 | if (soundURL.isLocalFile() && QFile::exists(fileName: soundURL.toLocalFile())) { |
93 | break; |
94 | } else if (!soundURL.isLocalFile() && soundURL.isValid()) { |
95 | break; |
96 | } |
97 | soundURL.clear(); |
98 | } |
99 | |
100 | #if HAVE_CANBERRA |
101 | if (!m_context) { |
102 | int ret = ca_context_create(c: &m_context); |
103 | if (ret != CA_SUCCESS) { |
104 | qCWarning(KNOTIFYCONFIG_LOG) << "Failed to initialize canberra context for audio notification:" << ca_strerror(code: ret); |
105 | m_context = nullptr; |
106 | return; |
107 | } |
108 | |
109 | QString desktopFileName = QGuiApplication::desktopFileName(); |
110 | // handle apps which set the desktopFileName property with filename suffix, |
111 | // due to unclear API dox (https://bugreports.qt.io/browse/QTBUG-75521) |
112 | if (desktopFileName.endsWith(s: QLatin1String(".desktop" ))) { |
113 | desktopFileName.chop(n: 8); |
114 | } |
115 | ret = ca_context_change_props(c: m_context, |
116 | CA_PROP_APPLICATION_NAME, |
117 | qUtf8Printable(qApp->applicationDisplayName()), |
118 | CA_PROP_APPLICATION_ID, |
119 | qUtf8Printable(desktopFileName), |
120 | CA_PROP_APPLICATION_ICON_NAME, |
121 | qUtf8Printable(qApp->windowIcon().name()), |
122 | nullptr); |
123 | if (ret != CA_SUCCESS) { |
124 | qCWarning(KNOTIFYCONFIG_LOG) << "Failed to set application properties on canberra context for audio notification:" << ca_strerror(code: ret); |
125 | } |
126 | } |
127 | |
128 | ca_proplist *props = nullptr; |
129 | ca_proplist_create(p: &props); |
130 | |
131 | // We'll also want this cached for a time. volatile makes sure the cache is |
132 | // dropped after some time or when the cache is under pressure. |
133 | ca_proplist_sets(p: props, CA_PROP_MEDIA_FILENAME, value: QFile::encodeName(fileName: soundURL.toLocalFile()).constData()); |
134 | ca_proplist_sets(p: props, CA_PROP_CANBERRA_CACHE_CONTROL, value: "volatile" ); |
135 | |
136 | int ret = ca_context_play_full(c: m_context, id: 0, p: props, cb: nullptr, userdata: nullptr); |
137 | |
138 | ca_proplist_destroy(p: props); |
139 | |
140 | if (ret != CA_SUCCESS) { |
141 | qCWarning(KNOTIFYCONFIG_LOG) << "Failed to play sound with canberra:" << ca_strerror(code: ret); |
142 | return; |
143 | } |
144 | #elif HAVE_PHONON |
145 | Phonon::MediaObject *media = Phonon::createPlayer(Phonon::NotificationCategory, soundURL); |
146 | media->play(); |
147 | connect(media, SIGNAL(finished()), media, SLOT(deleteLater())); |
148 | #endif |
149 | } |
150 | |
151 | #include "moc_knotifyconfigactionswidget.cpp" |
152 | |