[mutter/wip/carlosg/xwayland-on-demand: 12/32] core: Add MetaSound abstraction
- From: Carlos Garnacho <carlosg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [mutter/wip/carlosg/xwayland-on-demand: 12/32] core: Add MetaSound abstraction
- Date: Mon, 7 Jan 2019 12:49:25 +0000 (UTC)
commit 376ed4bd22fa1cdee9c82f8d5aa6f6b15616e705
Author: Carlos Garnacho <carlosg gnome org>
Date: Sun Dec 9 12:44:20 2018 +0100
core: Add MetaSound abstraction
This is a simple libcanberra abstraction object, so we are able
to play file/theme sounds without poking into GTK+/X11. Play
requests are delegated to a separate thread, so we don't block
UI on cards that are slow to wake up from power saving.
src/Makefile.am | 2 +
src/core/display-private.h | 2 +
src/core/display.c | 15 +++
src/core/meta-sound.c | 255 +++++++++++++++++++++++++++++++++++++++++++++
src/meson.build | 1 +
src/meta/display.h | 3 +
src/meta/meson.build | 1 +
src/meta/meta-sound.h | 19 ++++
8 files changed, 298 insertions(+)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index 1acf1de75..fba961fbd 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -296,6 +296,7 @@ libmutter_@LIBMUTTER_API_VERSION@_la_SOURCES = \
core/meta-memory-selection-source.c \
core/meta-selection.c \
core/meta-selection-source.c \
+ core/meta-sound.c \
core/delete.c \
core/display.c \
core/display-private.h \
@@ -595,6 +596,7 @@ libmutterinclude_headers = \
meta/meta-settings.h \
meta/meta-shaped-texture.h \
meta/meta-shadow-factory.h \
+ meta/meta-sound.h \
meta/meta-stage.h \
meta/meta-startup-notification.h \
meta/meta-window-actor.h \
diff --git a/src/core/display-private.h b/src/core/display-private.h
index 34c79daf5..58603d1a7 100644
--- a/src/core/display-private.h
+++ b/src/core/display-private.h
@@ -246,6 +246,8 @@ struct _MetaDisplay
MetaSelectionSource *selection_source;
GBytes *saved_clipboard;
MetaSelection *selection;
+
+ MetaSound *sound;
};
struct _MetaDisplayClass
diff --git a/src/core/display.c b/src/core/display.c
index d7fde5223..8dd9b4de0 100644
--- a/src/core/display.c
+++ b/src/core/display.c
@@ -67,6 +67,7 @@
#include "meta/main.h"
#include "meta/meta-backend.h"
#include "meta/meta-enum-types.h"
+#include "meta/meta-sound.h"
#include "meta/meta-x11-errors.h"
#include "meta/prefs.h"
#include "x11/meta-startup-notification-x11.h"
@@ -781,6 +782,8 @@ meta_display_open (void)
meta_idle_monitor_init_dbus ();
+ display->sound = g_object_new (META_TYPE_SOUND, NULL);
+
/* Done opening new display */
display->display_opening = FALSE;
@@ -3615,3 +3618,15 @@ meta_display_get_selection (MetaDisplay *display)
{
return display->selection;
}
+
+/**
+ * meta_display_get_sound:
+ * @display: a #MetaDisplay
+ *
+ * Returns: (transfer none): The sound platform abstraction of the display
+ */
+MetaSound *
+meta_display_get_sound (MetaDisplay *display)
+{
+ return display->sound;
+}
diff --git a/src/core/meta-sound.c b/src/core/meta-sound.c
new file mode 100644
index 000000000..3f04c96e1
--- /dev/null
+++ b/src/core/meta-sound.c
@@ -0,0 +1,255 @@
+#include "config.h"
+
+#include <canberra-gtk.h>
+#include "meta/meta-sound.h"
+
+#define EVENT_SOUNDS_KEY "event-sounds"
+#define THEME_NAME_KEY "theme-name"
+
+typedef struct _MetaSound MetaSound;
+typedef struct _MetaPlayRequest MetaPlayRequest;
+
+struct _MetaSound
+{
+ GObject parent_instance;
+ GThreadPool *queue;
+ GSettings *settings;
+ ca_context *context;
+ uint32_t id_pool;
+};
+
+struct _MetaPlayRequest
+{
+ ca_proplist *props;
+ uint32_t id;
+ GCancellable *cancellable;
+ MetaSound *sound;
+};
+
+const gchar * const cache_whitelist[] = {
+ "bell-window-system",
+ NULL
+};
+
+G_DEFINE_TYPE (MetaSound, meta_sound, G_TYPE_OBJECT)
+
+static MetaPlayRequest *
+meta_play_request_new (MetaSound *sound,
+ ca_proplist *props,
+ GCancellable *cancellable)
+{
+ MetaPlayRequest *req;
+
+ req = g_new0 (MetaPlayRequest, 1);
+ req->props = props;
+ req->cancellable = cancellable;
+ req->sound = sound;
+
+ return req;
+}
+
+static void
+meta_play_request_free (MetaPlayRequest *req)
+{
+ ca_proplist_destroy (req->props);
+ g_free (req);
+}
+
+static void
+meta_sound_finalize (GObject *object)
+{
+ MetaSound *sound = META_SOUND (object);
+
+ g_object_unref (sound->settings);
+ g_thread_pool_free (sound->queue, TRUE, TRUE);
+ ca_context_destroy (sound->context);
+
+ G_OBJECT_CLASS (meta_sound_parent_class)->finalize (object);
+}
+
+static void
+meta_sound_class_init (MetaSoundClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = meta_sound_finalize;
+}
+
+static void
+cancelled_cb (GCancellable *cancellable,
+ MetaPlayRequest *req)
+{
+ ca_context_cancel (req->sound->context, req->id);
+}
+
+static void
+finish_cb (ca_context *context,
+ uint32_t id,
+ int error_code,
+ gpointer user_data)
+{
+ MetaPlayRequest *req = user_data;
+
+ meta_play_request_free (req);
+}
+
+static void
+play_sound (MetaPlayRequest *req,
+ MetaSound *sound)
+{
+ req->id = sound->id_pool++;
+
+ if (ca_context_play_full (sound->context, req->id, req->props,
+ finish_cb, req) != CA_SUCCESS)
+ {
+ meta_play_request_free (req);
+ }
+ else
+ {
+ g_cancellable_connect (req->cancellable,
+ G_CALLBACK (cancelled_cb), req, NULL);
+ }
+}
+
+static void
+settings_changed_cb (GSettings *settings,
+ const gchar *key,
+ MetaSound *sound)
+{
+ if (strcmp (key, EVENT_SOUNDS_KEY) == 0)
+ {
+ gboolean enabled;
+
+ enabled = g_settings_get_boolean (settings, EVENT_SOUNDS_KEY);
+ ca_context_change_props (sound->context, CA_PROP_CANBERRA_ENABLE,
+ enabled ? "1" : "0", NULL);
+ }
+ else if (strcmp (key, THEME_NAME_KEY) == 0)
+ {
+ gchar *theme_name;
+
+ theme_name = g_settings_get_string (settings, THEME_NAME_KEY);
+ ca_context_change_props (sound->context, CA_PROP_CANBERRA_XDG_THEME_NAME,
+ theme_name, NULL);
+ g_free (theme_name);
+ }
+}
+
+static ca_context *
+create_context (GSettings *settings)
+{
+ ca_context *context;
+ ca_proplist *props;
+ gboolean enabled;
+ gchar *theme_name;
+
+ if (ca_context_create (&context) != CA_SUCCESS)
+ return NULL;
+
+ if (ca_proplist_create (&props) != CA_SUCCESS)
+ {
+ ca_context_destroy (context);
+ return NULL;
+ }
+
+ ca_proplist_sets (props, CA_PROP_APPLICATION_NAME, "Mutter");
+
+ enabled = g_settings_get_boolean (settings, EVENT_SOUNDS_KEY);
+ ca_proplist_sets (props, CA_PROP_CANBERRA_ENABLE, enabled ? "1" : "0");
+
+ theme_name = g_settings_get_string (settings, THEME_NAME_KEY);
+ ca_proplist_sets (props, CA_PROP_CANBERRA_XDG_THEME_NAME, theme_name);
+ g_free (theme_name);
+
+ ca_context_change_props_full (context, props);
+ ca_proplist_destroy (props);
+
+ return context;
+}
+
+static void
+meta_sound_init (MetaSound *sound)
+{
+ sound->queue = g_thread_pool_new ((GFunc) play_sound,
+ sound, 1, FALSE, NULL);
+ sound->settings = g_settings_new ("org.gnome.desktop.sound");
+ sound->context = create_context (sound->settings);
+
+ g_signal_connect (sound->settings, "changed",
+ G_CALLBACK (settings_changed_cb), sound);
+}
+
+static void
+build_ca_proplist (ca_proplist *props,
+ const char *event_property,
+ const char *event_id,
+ const char *event_description)
+{
+ ca_proplist_sets (props, event_property, event_id);
+ ca_proplist_sets (props, CA_PROP_EVENT_DESCRIPTION, event_description);
+}
+
+/**
+ * meta_sound_play_from_theme:
+ * @sound: a #MetaSound
+ * @name: sound theme name of the event
+ * @description: description of the event
+ * @cancellable: cancellable for the request
+ *
+ * Plays a sound from the sound theme.
+ **/
+void
+meta_sound_play_from_theme (MetaSound *sound,
+ const char *name,
+ const char *description,
+ GCancellable *cancellable)
+{
+ MetaPlayRequest *req;
+ ca_proplist *props;
+
+ ca_proplist_create (&props);
+ build_ca_proplist (props, CA_PROP_EVENT_ID, name, description);
+
+ if (g_strv_contains (cache_whitelist, name))
+ ca_proplist_sets (props, CA_PROP_CANBERRA_CACHE_CONTROL, "permanent");
+ else
+ ca_proplist_sets (props, CA_PROP_CANBERRA_CACHE_CONTROL, "volatile");
+
+ req = meta_play_request_new (sound, props, cancellable);
+ g_thread_pool_push (sound->queue, req, NULL);
+}
+
+/**
+ * meta_sound_play_from_file:
+ * @sound: a #MetaSound
+ * @file: file to play
+ * @description: description of the played sound
+ * @cancellable: cancellable for the request
+ *
+ * Plays a sound from a file.
+ **/
+void
+meta_sound_play_from_file (MetaSound *sound,
+ GFile *file,
+ const char *description,
+ GCancellable *cancellable)
+{
+ MetaPlayRequest *req;
+ ca_proplist *props;
+ gchar *path;
+
+ g_return_if_fail (META_IS_SOUND (sound));
+ g_return_if_fail (G_IS_FILE (file));
+ g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+ path = g_file_get_path (file);
+ g_return_if_fail (path != NULL);
+
+ ca_proplist_create (&props);
+ build_ca_proplist (props, CA_PROP_MEDIA_FILENAME, path, description);
+ ca_proplist_sets (props, CA_PROP_CANBERRA_CACHE_CONTROL, "volatile");
+ g_free (path);
+
+ req = meta_play_request_new (sound, props, cancellable);
+ g_thread_pool_push (sound->queue, req, NULL);
+}
diff --git a/src/meson.build b/src/meson.build
index 28158bec7..abdeee99a 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -336,6 +336,7 @@ mutter_sources = [
'core/meta-memory-selection-source.c',
'core/meta-selection.c',
'core/meta-selection-source.c',
+ 'core/meta-sound.c',
'core/meta-workspace-manager.c',
'core/meta-workspace-manager-private.h',
'core/place.c',
diff --git a/src/meta/display.h b/src/meta/display.h
index fd25559ed..6f80567bd 100644
--- a/src/meta/display.h
+++ b/src/meta/display.h
@@ -27,6 +27,7 @@
#include <meta/prefs.h>
#include <meta/common.h>
#include <meta/workspace.h>
+#include <meta/meta-sound.h>
#include <meta/meta-startup-notification.h>
/**
@@ -232,4 +233,6 @@ MetaStartupNotification * meta_display_get_startup_notification (MetaDisplay *di
MetaSelection * meta_display_get_selection (MetaDisplay *display);
+MetaSound * meta_display_get_sound (MetaDisplay *display);
+
#endif
diff --git a/src/meta/meson.build b/src/meta/meson.build
index 87880de22..ddca7e148 100644
--- a/src/meta/meson.build
+++ b/src/meta/meson.build
@@ -27,6 +27,7 @@ mutter_public_headers = [
'meta-settings.h',
'meta-shadow-factory.h',
'meta-shaped-texture.h',
+ 'meta-sound.h',
'meta-stage.h',
'meta-startup-notification.h',
'meta-window-actor.h',
diff --git a/src/meta/meta-sound.h b/src/meta/meta-sound.h
new file mode 100644
index 000000000..a7b4133ba
--- /dev/null
+++ b/src/meta/meta-sound.h
@@ -0,0 +1,19 @@
+#ifndef META_SOUND_H
+#define META_SOUND_H
+
+#include <gio/gio.h>
+
+G_DECLARE_FINAL_TYPE (MetaSound, meta_sound, META, SOUND, GObject)
+
+#define META_TYPE_SOUND (meta_sound_get_type ())
+
+void meta_sound_play_from_theme (MetaSound *sound,
+ const char *name,
+ const char *description,
+ GCancellable *cancellable);
+void meta_sound_play_from_file (MetaSound *sound,
+ GFile *file,
+ const char *description,
+ GCancellable *cancellable);
+
+#endif /* META_SOUND_H */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]