[gnome-shell/bilelmoussaoui/libcanberra-sound] sound player: Add Shell implementation of mutter#2375
- From: Bilal Elmoussaoui <bilelmoussaoui src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-shell/bilelmoussaoui/libcanberra-sound] sound player: Add Shell implementation of mutter#2375
- Date: Thu, 14 Apr 2022 10:35:26 +0000 (UTC)
commit 5961bf13052b9634a47fb645a9ebbb93e907eea0
Author: Bilal Elmoussaoui <belmouss redhat com>
Date: Thu Apr 14 12:35:09 2022 +0200
sound player: Add Shell implementation of mutter#2375
meson.build | 2 +
src/gnome-shell-plugin.c | 11 ++
src/meson.build | 5 +-
src/shell-global-private.h | 4 +
src/shell-global.c | 19 ++++
src/shell-sound-player.c | 262 +++++++++++++++++++++++++++++++++++++++++++++
src/shell-sound-player.h | 37 +++++++
7 files changed, 339 insertions(+), 1 deletion(-)
---
diff --git a/meson.build b/meson.build
index 8d7478f9b2..243d6d6938 100644
--- a/meson.build
+++ b/meson.build
@@ -31,6 +31,7 @@ schemas_req = '>= 42.beta'
startup_req = '>= 0.11'
ibus_req = '>= 1.5.19'
gnome_desktop_req = '>= 3.35.90'
+libcanberra_req = '>= 0.26'
bt_req = '>= 3.9.0'
gst_req = '>= 0.11.92'
@@ -97,6 +98,7 @@ bt_dep = dependency('gnome-bluetooth-3.0', version: bt_req, required: false)
gst_dep = dependency('gstreamer-1.0', version: gst_req, required: false)
gst_base_dep = dependency('gstreamer-base-1.0', required: false)
pipewire_dep = dependency('libpipewire-0.3', required: false)
+libcanberra_dep = dependency('libcanberra', version: libcanberra_req)
recorder_deps = []
enable_recorder = gst_dep.found() and gst_base_dep.found() and pipewire_dep.found()
diff --git a/src/gnome-shell-plugin.c b/src/gnome-shell-plugin.c
index 5364f043a0..c25d5b68e2 100644
--- a/src/gnome-shell-plugin.c
+++ b/src/gnome-shell-plugin.c
@@ -352,6 +352,15 @@ gnome_shell_plugin_locate_pointer (MetaPlugin *plugin)
_shell_global_locate_pointer (shell_plugin->global);
}
+static void
+gnome_shell_plugin_play_sound (MetaPlugin *plugin,
+ const char *name,
+ const char *description)
+{
+ GnomeShellPlugin *shell_plugin = GNOME_SHELL_PLUGIN (plugin);
+ _shell_global_play_sound (shell_plugin->global, name, description);
+}
+
static void
gnome_shell_plugin_class_init (GnomeShellPluginClass *klass)
{
@@ -385,6 +394,8 @@ gnome_shell_plugin_class_init (GnomeShellPluginClass *klass)
plugin_class->create_close_dialog = gnome_shell_plugin_create_close_dialog;
plugin_class->create_inhibit_shortcuts_dialog = gnome_shell_plugin_create_inhibit_shortcuts_dialog;
+ plugin_class->play_sound = gnome_shell_plugin_play_sound;
+
plugin_class->locate_pointer = gnome_shell_plugin_locate_pointer;
}
diff --git a/src/meson.build b/src/meson.build
index 8dd0887c63..237e83ada4 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -61,7 +61,8 @@ gnome_shell_deps = [
gi_dep,
polkit_dep,
gcr_dep,
- libsystemd_dep
+ libsystemd_dep,
+ libcanberra_dep,
]
gnome_shell_deps += nm_deps
@@ -151,6 +152,8 @@ libshell_sources = [
'shell-secure-text-buffer.c',
'shell-secure-text-buffer.h',
'shell-square-bin.c',
+ 'shell-sound-player.c',
+ 'shell-sound-player.h',
'shell-stack.c',
'shell-tray-icon.c',
'shell-tray-manager.c',
diff --git a/src/shell-global-private.h b/src/shell-global-private.h
index 9969691cb4..1e37267f15 100644
--- a/src/shell-global-private.h
+++ b/src/shell-global-private.h
@@ -20,4 +20,8 @@ gboolean _shell_global_check_xdnd_event (ShellGlobal *global,
void _shell_global_locate_pointer (ShellGlobal *global);
+void _shell_global_play_sound (ShellGlobal *global,
+ const char *name,
+ const char *description);
+
#endif /* __SHELL_GLOBAL_PRIVATE_H__ */
diff --git a/src/shell-global.c b/src/shell-global.c
index efe1271b5a..eddb104894 100644
--- a/src/shell-global.c
+++ b/src/shell-global.c
@@ -39,6 +39,7 @@
#include "shell-enum-types.h"
#include "shell-global-private.h"
#include "shell-perf-log.h"
+#include "shell-sound-player.h"
#include "shell-window-tracker.h"
#include "shell-wm.h"
#include "shell-util.h"
@@ -83,6 +84,8 @@ struct _ShellGlobal {
gboolean frame_timestamps;
gboolean frame_finish_timestamp;
+ ShellSoundPlayer *sound_player;
+
GDBusProxy *switcheroo_control;
GCancellable *switcheroo_cancellable;
};
@@ -390,6 +393,8 @@ shell_global_init (ShellGlobal *global)
byteorder_string = "BE";
#endif
+ global->sound_player = g_object_new (SHELL_TYPE_SOUND_PLAYER, NULL);
+
/* And the runtime state */
path = g_strdup_printf ("%s/gnome-shell/runtime-state-%s.%s",
g_get_user_runtime_dir (),
@@ -473,6 +478,8 @@ shell_global_finalize (GObject *object)
g_clear_object (&global->userdatadir_path);
g_clear_object (&global->runtime_state_path);
+ g_clear_object (&global->sound_player);
+
g_free (global->session_mode);
g_free (global->imagedir);
g_free (global->userdatadir);
@@ -1842,3 +1849,15 @@ _shell_global_locate_pointer (ShellGlobal *global)
{
g_signal_emit (global, shell_global_signals[LOCATE_POINTER], 0);
}
+
+
+void
+_shell_global_play_sound (ShellGlobal *global,
+ const char *name,
+ const char *description)
+{
+ shell_sound_player_play_from_theme (global->sound_player,
+ name,
+ description,
+ NULL);
+}
diff --git a/src/shell-sound-player.c b/src/shell-sound-player.c
new file mode 100644
index 0000000000..ba6fddaa62
--- /dev/null
+++ b/src/shell-sound-player.c
@@ -0,0 +1,262 @@
+/*
+ * Copyright (C) 2018 Red Hat
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Author: Carlos Garnacho <carlosg gnome org>
+ */
+
+#include "config.h"
+
+#include <canberra.h>
+
+#include "shell-sound-player.h"
+
+#define EVENT_SOUNDS_KEY "event-sounds"
+#define THEME_NAME_KEY "theme-name"
+
+typedef struct _ShellPlayRequest ShellPlayRequest;
+
+struct _ShellSoundPlayer
+{
+ GObject parent;
+ GThreadPool *queue;
+ GSettings *settings;
+ ca_context *context;
+ uint32_t id_pool;
+};
+
+struct _ShellPlayRequest
+{
+ ca_proplist *props;
+ uint32_t id;
+ gulong cancel_id;
+ GCancellable *cancellable;
+ ShellSoundPlayer *player;
+};
+
+const char * const cache_allow_list[] = {
+ "bell-window-system",
+ "desktop-switch-left",
+ "desktop-switch-right",
+ "desktop-switch-up",
+ "desktop-switch-down",
+ NULL
+};
+
+G_DEFINE_TYPE (ShellSoundPlayer, shell_sound_player, G_TYPE_OBJECT)
+
+static ShellPlayRequest *
+shell_play_request_new (ShellSoundPlayer *player,
+ ca_proplist *props,
+ GCancellable *cancellable)
+{
+ ShellPlayRequest *req;
+
+ req = g_new0 (ShellPlayRequest, 1);
+ req->props = props;
+ req->player = player;
+ g_set_object (&req->cancellable, cancellable);
+
+ return req;
+}
+
+static void
+shell_play_request_free (ShellPlayRequest *req)
+{
+ g_clear_object (&req->cancellable);
+ ca_proplist_destroy (req->props);
+ g_free (req);
+}
+
+static void
+shell_sound_player_finalize (GObject *object)
+{
+ ShellSoundPlayer *player = SHELL_SOUND_PLAYER (object);
+
+ g_object_unref (player->settings);
+ g_thread_pool_free (player->queue, FALSE, TRUE);
+ ca_context_destroy (player->context);
+
+ G_OBJECT_CLASS (shell_sound_player_parent_class)->finalize (object);
+}
+
+static void
+shell_sound_player_class_init (ShellSoundPlayerClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = shell_sound_player_finalize;
+}
+
+static void
+cancelled_cb (GCancellable *cancellable,
+ ShellPlayRequest *req)
+{
+ ca_context_cancel (req->player->context, req->id);
+}
+
+static void
+finish_cb (ca_context *context,
+ uint32_t id,
+ int error_code,
+ gpointer user_data)
+{
+ ShellPlayRequest *req = user_data;
+
+ if (error_code != CA_ERROR_CANCELED)
+ g_cancellable_disconnect (req->cancellable, req->cancel_id);
+ else if (req->cancellable != NULL)
+ g_clear_signal_handler (&req->cancel_id, req->cancellable);
+
+ shell_play_request_free (req);
+}
+
+static void
+play_sound (ShellPlayRequest *req,
+ ShellSoundPlayer *player)
+{
+ req->id = player->id_pool++;
+
+ if (ca_context_play_full (player->context, req->id, req->props,
+ finish_cb, req) != CA_SUCCESS)
+ {
+ shell_play_request_free (req);
+ return;
+ }
+
+ if (req->cancellable)
+ {
+ gulong cancel_id =
+ g_cancellable_connect (req->cancellable,
+ G_CALLBACK (cancelled_cb), req, NULL);
+ if (cancel_id)
+ req->cancel_id = cancel_id;
+ }
+}
+
+static void
+settings_changed_cb (GSettings *settings,
+ const char *key,
+ ShellSoundPlayer *player)
+{
+ if (strcmp (key, EVENT_SOUNDS_KEY) == 0)
+ {
+ gboolean enabled;
+
+ enabled = g_settings_get_boolean (settings, EVENT_SOUNDS_KEY);
+ ca_context_change_props (player->context, CA_PROP_CANBERRA_ENABLE,
+ enabled ? "1" : "0", NULL);
+ }
+ else if (strcmp (key, THEME_NAME_KEY) == 0)
+ {
+ char *theme_name;
+
+ theme_name = g_settings_get_string (settings, THEME_NAME_KEY);
+ ca_context_change_props (player->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;
+ char *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
+shell_sound_player_init (ShellSoundPlayer *player)
+{
+ player->queue = g_thread_pool_new ((GFunc) play_sound,
+ player, 1, FALSE, NULL);
+ player->settings = g_settings_new ("org.gnome.desktop.sound");
+ player->context = create_context (player->settings);
+
+ g_signal_connect (player->settings, "changed",
+ G_CALLBACK (settings_changed_cb), player);
+}
+
+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);
+}
+
+/**
+ * shell_sound_player_play_from_theme:
+ * @player: a #ShellSoundPlayer
+ * @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
+shell_sound_player_play_from_theme (ShellSoundPlayer *player,
+ const char *name,
+ const char *description,
+ GCancellable *cancellable)
+{
+ ShellPlayRequest *req;
+ ca_proplist *props;
+
+ g_return_if_fail (SHELL_IS_SOUND_PLAYER (player));
+ g_return_if_fail (name != NULL);
+ g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+ ca_proplist_create (&props);
+ build_ca_proplist (props, CA_PROP_EVENT_ID, name, description);
+
+ if (g_strv_contains (cache_allow_list, name))
+ ca_proplist_sets (props, CA_PROP_CANBERRA_CACHE_CONTROL, "permanent");
+ else
+ ca_proplist_sets (props, CA_PROP_CANBERRA_CACHE_CONTROL, "volatile");
+
+ req = shell_play_request_new (player, props, cancellable);
+ g_thread_pool_push (player->queue, req, NULL);
+}
+
diff --git a/src/shell-sound-player.h b/src/shell-sound-player.h
new file mode 100644
index 0000000000..4c9e6c3d25
--- /dev/null
+++ b/src/shell-sound-player.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2018 Red Hat
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Author: Carlos Garnacho <carlosg gnome org>
+ */
+#ifndef SHELL_SOUND_PLAYER_H
+#define SHELL_SOUND_PLAYER_H
+
+#include <gio/gio.h>
+
+#define SHELL_TYPE_SOUND_PLAYER (shell_sound_player_get_type ())
+
+G_DECLARE_FINAL_TYPE (ShellSoundPlayer, shell_sound_player,
+ SHELL, SOUND_PLAYER, GObject)
+
+
+void shell_sound_player_play_from_theme (ShellSoundPlayer *player,
+ const char *name,
+ const char *description,
+ GCancellable *cancellable);
+
+#endif /* SHELL_SOUND_PLAYER_H */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]