1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
3
* Copyright (C) 2008 Lennart Poettering <lennart@poettering.net>
5
* This program is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation; either version 2 of the License, or
8
* (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software
17
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23
#include <sys/types.h>
35
#include <glib/gi18n.h>
37
#include <pulse/pulseaudio.h>
39
#include "gsd-sound-manager.h"
40
#include "gnome-settings-profile.h"
42
#define GSD_SOUND_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSD_TYPE_SOUND_MANAGER, GsdSoundManagerPrivate))
44
struct GsdSoundManagerPrivate
51
static void gsd_sound_manager_class_init (GsdSoundManagerClass *klass);
52
static void gsd_sound_manager_init (GsdSoundManager *sound_manager);
53
static void gsd_sound_manager_finalize (GObject *object);
55
G_DEFINE_TYPE (GsdSoundManager, gsd_sound_manager, G_TYPE_OBJECT)
57
static gpointer manager_object = NULL;
60
sample_info_cb (pa_context *c, const pa_sample_info *i, int eol, void *userdata)
67
g_debug ("Found sample %s", i->name);
69
/* We only flush those samples which have an XDG sound name
70
* attached, because only those originate from themeing */
71
if (!(pa_proplist_gets (i->proplist, PA_PROP_EVENT_ID)))
74
g_debug ("Dropping sample %s from cache", i->name);
76
if (!(o = pa_context_remove_sample (c, i->name, NULL, NULL))) {
77
g_debug ("pa_context_remove_sample (): %s", pa_strerror (pa_context_errno (c)));
81
pa_operation_unref (o);
83
/* We won't wait until the operation is actually executed to
84
* speed things up a bit.*/
90
pa_mainloop *ml = NULL;
92
pa_proplist *pl = NULL;
93
pa_operation *o = NULL;
95
g_debug ("Flushing sample cache");
97
if (!(ml = pa_mainloop_new ())) {
98
g_debug ("Failed to allocate pa_mainloop");
102
if (!(pl = pa_proplist_new ())) {
103
g_debug ("Failed to allocate pa_proplist");
107
pa_proplist_sets (pl, PA_PROP_APPLICATION_NAME, PACKAGE_NAME);
108
pa_proplist_sets (pl, PA_PROP_APPLICATION_VERSION, PACKAGE_VERSION);
109
pa_proplist_sets (pl, PA_PROP_APPLICATION_ID, "org.gnome.SettingsDaemon");
111
if (!(c = pa_context_new_with_proplist (pa_mainloop_get_api (ml), PACKAGE_NAME, pl))) {
112
g_debug ("Failed to allocate pa_context");
116
pa_proplist_free (pl);
119
if (pa_context_connect (c, NULL, PA_CONTEXT_NOAUTOSPAWN, NULL) < 0) {
120
g_debug ("pa_context_connect(): %s", pa_strerror (pa_context_errno (c)));
124
/* Wait until the connection is established */
125
while (pa_context_get_state (c) != PA_CONTEXT_READY) {
127
if (!PA_CONTEXT_IS_GOOD (pa_context_get_state (c))) {
128
g_debug ("Connection failed: %s", pa_strerror (pa_context_errno (c)));
132
if (pa_mainloop_iterate (ml, TRUE, NULL) < 0) {
133
g_debug ("pa_mainloop_iterate() failed");
138
/* Enumerate all cached samples */
139
if (!(o = pa_context_get_sample_info_list (c, sample_info_cb, NULL))) {
140
g_debug ("pa_context_get_sample_info_list(): %s", pa_strerror (pa_context_errno (c)));
144
/* Wait until our operation is finished and there's nothing
145
* more queued to send to the server */
146
while (pa_operation_get_state (o) == PA_OPERATION_RUNNING || pa_context_is_pending (c)) {
148
if (!PA_CONTEXT_IS_GOOD (pa_context_get_state (c))) {
149
g_debug ("Connection failed: %s", pa_strerror (pa_context_errno (c)));
153
if (pa_mainloop_iterate (ml, TRUE, NULL) < 0) {
154
g_debug ("pa_mainloop_iterate() failed");
159
g_debug ("Sample cache flushed");
163
pa_operation_cancel (o);
164
pa_operation_unref (o);
168
pa_context_disconnect (c);
169
pa_context_unref (c);
173
pa_proplist_free (pl);
176
pa_mainloop_free (ml);
180
flush_cb (GsdSoundManager *manager)
183
manager->priv->timeout = 0;
188
trigger_flush (GsdSoundManager *manager)
191
if (manager->priv->timeout)
192
g_source_remove (manager->priv->timeout);
194
/* We delay the flushing a bit so that we can coalesce
195
* multiple changes into a single cache flush */
196
manager->priv->timeout = g_timeout_add (500, (GSourceFunc) flush_cb, manager);
200
settings_changed_cb (GSettings *settings,
202
GsdSoundManager *manager)
204
trigger_flush (manager);
208
register_config_callback (GsdSoundManager *manager)
210
manager->priv->settings = g_settings_new ("org.gnome.desktop.sound");
211
g_signal_connect (G_OBJECT (manager->priv->settings), "changed",
212
G_CALLBACK (settings_changed_cb), manager);
216
file_monitor_changed_cb (GFileMonitor *monitor,
219
GFileMonitorEvent event,
220
GsdSoundManager *manager)
222
g_debug ("Theme dir changed");
223
trigger_flush (manager);
227
register_directory_callback (GsdSoundManager *manager,
233
gboolean succ = FALSE;
235
g_debug ("Registering directory monitor for %s", path);
237
f = g_file_new_for_path (path);
239
m = g_file_monitor_directory (f, 0, NULL, error);
242
g_signal_connect (m, "changed", G_CALLBACK (file_monitor_changed_cb), manager);
244
manager->priv->monitors = g_list_prepend (manager->priv->monitors, m);
255
gsd_sound_manager_start (GsdSoundManager *manager,
259
const gchar * const * dirs;
262
g_debug ("Starting sound manager");
263
gnome_settings_profile_start (NULL);
265
/* We listen for change of the selected theme ... */
266
register_config_callback (manager);
268
/* ... and we listen to changes of the theme base directories
270
p = g_build_filename (g_get_user_data_dir (), "sounds", NULL);
271
register_directory_callback (manager, p, NULL);
274
/* ... and globally. */
275
dirs = g_get_system_data_dirs ();
276
for (i = 0; dirs[i] != NULL; i++) {
277
p = g_build_filename (dirs[i], "sounds", NULL);
278
register_directory_callback (manager, p, NULL);
282
gnome_settings_profile_end (NULL);
288
gsd_sound_manager_stop (GsdSoundManager *manager)
290
g_debug ("Stopping sound manager");
292
if (manager->priv->settings != NULL) {
293
g_object_unref (manager->priv->settings);
294
manager->priv->settings = NULL;
297
if (manager->priv->timeout) {
298
g_source_remove (manager->priv->timeout);
299
manager->priv->timeout = 0;
302
while (manager->priv->monitors) {
303
g_file_monitor_cancel (G_FILE_MONITOR (manager->priv->monitors->data));
304
g_object_unref (manager->priv->monitors->data);
305
manager->priv->monitors = g_list_delete_link (manager->priv->monitors, manager->priv->monitors);
310
gsd_sound_manager_constructor (
312
guint n_construct_properties,
313
GObjectConstructParam *construct_properties)
317
m = GSD_SOUND_MANAGER (G_OBJECT_CLASS (gsd_sound_manager_parent_class)->constructor (
319
n_construct_properties,
320
construct_properties));
326
gsd_sound_manager_dispose (GObject *object)
328
GsdSoundManager *manager;
330
manager = GSD_SOUND_MANAGER (object);
332
gsd_sound_manager_stop (manager);
334
G_OBJECT_CLASS (gsd_sound_manager_parent_class)->dispose (object);
338
gsd_sound_manager_class_init (GsdSoundManagerClass *klass)
340
GObjectClass *object_class = G_OBJECT_CLASS (klass);
342
object_class->constructor = gsd_sound_manager_constructor;
343
object_class->dispose = gsd_sound_manager_dispose;
344
object_class->finalize = gsd_sound_manager_finalize;
346
g_type_class_add_private (klass, sizeof (GsdSoundManagerPrivate));
350
gsd_sound_manager_init (GsdSoundManager *manager)
352
manager->priv = GSD_SOUND_MANAGER_GET_PRIVATE (manager);
356
gsd_sound_manager_finalize (GObject *object)
358
GsdSoundManager *sound_manager;
360
g_return_if_fail (object != NULL);
361
g_return_if_fail (GSD_IS_SOUND_MANAGER (object));
363
sound_manager = GSD_SOUND_MANAGER (object);
365
g_return_if_fail (sound_manager->priv);
367
G_OBJECT_CLASS (gsd_sound_manager_parent_class)->finalize (object);
371
gsd_sound_manager_new (void)
373
if (manager_object) {
374
g_object_ref (manager_object);
376
manager_object = g_object_new (GSD_TYPE_SOUND_MANAGER, NULL);
377
g_object_add_weak_pointer (manager_object, (gpointer *) &manager_object);
380
return GSD_SOUND_MANAGER (manager_object);