Commit 580c1d0a authored by Robert Ancell's avatar Robert Ancell

sound: Implement updated design

parent 89b3eb36
Pipeline #41488 failed with stages
in 1 minute and 6 seconds
......@@ -46,6 +46,8 @@ build:
stage: build
script:
- dnf -y install gsound-devel # FIXME: Remove when new images built
- *environment_information
- *build_procedure
......
......@@ -14,7 +14,7 @@ RUN dnf -y --nogpgcheck upgrade && \
colord-gtk-devel cups-devel desktop-file-utils docbook-style-xsl gdk-pixbuf2-devel \
gettext git glib2-devel gnome-bluetooth-libs-devel gnome-desktop3-devel \
gnome-online-accounts-devel gnome-settings-daemon-devel grilo-devel \
gsettings-desktop-schemas-devel gtk3-devel ibus-devel intltool libcanberra-devel \
gsettings-desktop-schemas-devel gsound-devel gtk3-devel ibus-devel intltool libcanberra-devel \
libgtop2-devel libgudev-devel libnma-devel libpwquality-devel libsmbclient-devel \
libsoup-devel libwacom-devel libX11-devel libXi-devel libxml2-devel libxslt \
libXxf86misc-devel meson ModemManager-glib-devel NetworkManager-libnm-devel \
......
......@@ -12,7 +12,7 @@ RUN dnf -y --nogpgcheck upgrade && \
colord-gtk-devel cups-devel desktop-file-utils docbook-style-xsl gdk-pixbuf2-devel \
gettext git glib2-devel gnome-bluetooth-libs-devel gnome-desktop3-devel \
gnome-online-accounts-devel gnome-settings-daemon-devel grilo-devel \
gsettings-desktop-schemas-devel gtk3-devel ibus-devel intltool libcanberra-devel \
gsettings-desktop-schemas-devel gsound-devel gtk3-devel ibus-devel intltool libcanberra-devel \
libgtop2-devel libgudev-devel libnma-devel libpwquality-devel libsmbclient-devel \
libsoup-devel libwacom-devel libX11-devel libXi-devel libxml2-devel libxslt \
libXxf86misc-devel meson ModemManager-glib-devel NetworkManager-libnm-devel \
......
......@@ -14,7 +14,7 @@ RUN dnf -y --nogpgcheck upgrade && \
colord-gtk-devel cups-devel desktop-file-utils docbook-style-xsl gdk-pixbuf2-devel \
gettext git glib2-devel gnome-bluetooth-libs-devel gnome-desktop3-devel \
gnome-online-accounts-devel gnome-settings-daemon-devel grilo-devel \
gsettings-desktop-schemas-devel gtk3-devel ibus-devel intltool libcanberra-devel \
gsettings-desktop-schemas-devel gsound-devel gtk3-devel ibus-devel intltool libcanberra-devel \
libgtop2-devel libgudev-devel libnma-devel libpwquality-devel libsmbclient-devel \
libsoup-devel libwacom-devel libX11-devel libXi-devel libxml2-devel libxslt \
libXxf86misc-devel meson ModemManager-glib-devel NetworkManager-libnm-devel \
......
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2018 Canonical Ltd.
*
* 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <glib/gi18n.h>
#include <gsound.h>
#include "config.h"
#include "cc-alert-chooser.h"
#include "cc-sound-button.h"
#include "cc-sound-resources.h"
#define KEY_SOUNDS_SCHEMA "org.gnome.desktop.sound"
struct _CcAlertChooser
{
GtkBox parent_instance;
CcSoundButton *bark_button;
CcSoundButton *drip_button;
CcSoundButton *glass_button;
CcSoundButton *sonar_button;
GSoundContext *context;
GSettings *sound_settings;
};
G_DEFINE_TYPE (CcAlertChooser, cc_alert_chooser, GTK_TYPE_BOX)
#define CUSTOM_THEME_NAME "__custom"
static gchar *
get_theme_dir (void)
{
return g_build_filename (g_get_user_data_dir (), "sounds", CUSTOM_THEME_NAME, NULL);
}
static gchar *
get_sound_path (const gchar *name)
{
g_autofree gchar *filename = NULL;
filename = g_strdup_printf ("%s.ogg", name);
return g_build_filename (SOUND_DATA_DIR, "gnome", "default", "alerts", filename, NULL);
}
static gchar *
get_alert_name (void)
{
g_autofree gchar *dir = NULL;
g_autofree gchar *path = NULL;
g_autoptr(GFile) file = NULL;
g_autoptr(GFileInfo) info = NULL;
const gchar *target;
g_autofree gchar *basename = NULL;
g_autoptr(GError) error = NULL;
dir = get_theme_dir ();
path = g_build_filename (dir, "bell-terminal.ogg", NULL);
file = g_file_new_for_path (path);
info = g_file_query_info (file,
G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET,
G_FILE_QUERY_INFO_NONE,
NULL,
&error);
if (info == NULL)
{
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
g_warning ("Failed to get sound theme symlink %s: %s", path, error->message);
return NULL;
}
target = g_file_info_get_attribute_byte_string (info, G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET);
if (target == NULL)
return NULL;
basename = g_path_get_basename (target);
if (g_str_has_suffix (basename, ".ogg"))
basename[strlen (basename) - 4] = '\0';
return g_steal_pointer (&basename);
}
static void
set_sound_symlink (const gchar *alert_name,
const gchar *name)
{
g_autofree gchar *dir = NULL;
g_autofree gchar *source_filename = NULL;
g_autofree gchar *source_path = NULL;
g_autofree gchar *target_path = NULL;
g_autoptr(GFile) file = NULL;
g_autoptr(GError) error = NULL;
dir = get_theme_dir ();
source_filename = g_strdup_printf ("%s.ogg", alert_name);
source_path = g_build_filename (dir, source_filename, NULL);
target_path = get_sound_path (name);
file = g_file_new_for_path (source_path);
if (!g_file_delete (file, NULL, &error))
{
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
g_warning ("Failed to remove existing sound symbolic link %s: %s", source_path, error->message);
}
if (!g_file_make_symbolic_link (file, target_path, NULL, &error))
g_warning ("Failed to make sound theme symbolic link %s->%s: %s", source_path, target_path, error->message);
}
static void
set_custom_theme (CcAlertChooser *self,
const gchar *name)
{
g_autofree gchar *dir = NULL;
g_autofree gchar *theme_path = NULL;
g_autoptr(GKeyFile) theme_file = NULL;
g_autoptr(GVariant) default_theme = NULL;
g_autoptr(GError) load_error = NULL;
g_autoptr(GError) save_error = NULL;
dir = get_theme_dir ();
g_mkdir_with_parents (dir, USER_DIR_MODE);
theme_path = g_build_filename (dir, "index.theme", NULL);
default_theme = g_settings_get_default_value (self->sound_settings, "theme-name");
theme_file = g_key_file_new ();
if (!g_key_file_load_from_file (theme_file, theme_path, G_KEY_FILE_KEEP_COMMENTS, &load_error))
{
if (!g_error_matches (load_error, G_FILE_ERROR, G_FILE_ERROR_NOENT))
g_printerr ("Failed to load theme file %s: %s", theme_path, load_error->message);
}
g_key_file_set_string (theme_file, "Sound Theme", "Name", _("Custom"));
if (default_theme != NULL)
g_key_file_set_string (theme_file, "Sound Theme", "Inherits", g_variant_get_string (default_theme, NULL));
g_key_file_set_string (theme_file, "Sound Theme", "Directories", ".");
if (!g_key_file_save_to_file (theme_file, theme_path, &save_error))
g_warning ("Failed to save theme file %s: %s", theme_path, save_error->message);
set_sound_symlink ("bell-terminal", name);
set_sound_symlink ("bell-window-system", name);
g_settings_set_boolean (self->sound_settings, "event-sounds", TRUE);
g_settings_set_string (self->sound_settings, "theme-name", CUSTOM_THEME_NAME);
}
static void
select_sound (CcAlertChooser *self,
const gchar *name)
{
g_autofree gchar *path = NULL;
g_autoptr(GError) error = NULL;
path = get_sound_path (name);
if (!gsound_context_play_simple (self->context, NULL, &error,
GSOUND_ATTR_MEDIA_FILENAME, path,
NULL))
g_warning ("Failed to play alert sound %s: %s", path, error->message);
set_custom_theme (self, name);
}
static void
clicked_cb (CcAlertChooser *self,
CcSoundButton *button);
static void
set_button (CcAlertChooser *self,
CcSoundButton *button,
gboolean active)
{
g_signal_handlers_block_by_func (button, clicked_cb, self);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), active);
g_signal_handlers_unblock_by_func (button, clicked_cb, self);
}
static void
clicked_cb (CcAlertChooser *self,
CcSoundButton *button)
{
if (button == self->bark_button)
select_sound (self, "bark");
else if (button == self->drip_button)
select_sound (self, "drip");
else if (button == self->glass_button)
select_sound (self, "glass");
else if (button == self->sonar_button)
select_sound (self, "sonar");
set_button (self, button, TRUE);
if (button != self->bark_button)
set_button (self, self->bark_button, FALSE);
if (button != self->drip_button)
set_button (self, self->drip_button, FALSE);
if (button != self->glass_button)
set_button (self, self->glass_button, FALSE);
if (button != self->sonar_button)
set_button (self, self->sonar_button, FALSE);
}
static void
cc_alert_chooser_dispose (GObject *object)
{
CcAlertChooser *self = CC_ALERT_CHOOSER (object);
g_clear_object (&self->context);
g_clear_object (&self->sound_settings);
G_OBJECT_CLASS (cc_alert_chooser_parent_class)->dispose (object);
}
void
cc_alert_chooser_class_init (CcAlertChooserClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
object_class->dispose = cc_alert_chooser_dispose;
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/sound/cc-alert-chooser.ui");
gtk_widget_class_bind_template_child (widget_class, CcAlertChooser, bark_button);
gtk_widget_class_bind_template_child (widget_class, CcAlertChooser, drip_button);
gtk_widget_class_bind_template_child (widget_class, CcAlertChooser, glass_button);
gtk_widget_class_bind_template_child (widget_class, CcAlertChooser, sonar_button);
gtk_widget_class_bind_template_callback (widget_class, clicked_cb);
}
void
cc_alert_chooser_init (CcAlertChooser *self)
{
g_autofree gchar *alert_name = NULL;
g_autoptr(GError) error = NULL;
g_resources_register (cc_sound_get_resource ());
cc_sound_button_get_type ();
gtk_widget_init_template (GTK_WIDGET (self));
self->context = gsound_context_new (NULL, &error);
if (self->context == NULL)
g_error ("Failed to make sound context: %s", error->message);
self->sound_settings = g_settings_new (KEY_SOUNDS_SCHEMA);
alert_name = get_alert_name ();
if (g_strcmp0 (alert_name, "bark") == 0)
set_button (self, self->bark_button, TRUE);
else if (g_strcmp0 (alert_name, "drip") == 0)
set_button (self, self->drip_button, TRUE);
else if (g_strcmp0 (alert_name, "glass") == 0)
set_button (self, self->glass_button, TRUE);
else if (g_strcmp0 (alert_name, "sonar") == 0)
set_button (self, self->sonar_button, TRUE);
else if (alert_name != NULL)
g_warning ("Current alert sound has unknown name %s", alert_name);
}
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2018 Canonical Ltd.
*
* 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <gtk/gtk.h>
G_BEGIN_DECLS
#define CC_TYPE_ALERT_CHOOSER (cc_alert_chooser_get_type ())
G_DECLARE_FINAL_TYPE (CcAlertChooser, cc_alert_chooser, CC, ALERT_CHOOSER, GtkBox)
G_END_DECLS
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<!-- interface-requires gtk+ 3.0 -->
<template class="CcAlertChooser" parent="GtkBox">
<property name="homogeneous">True</property>
<child>
<object class="CcSoundButton" id="bark_button">
<property name="visible">True</property>
<property name="label" translatable="yes">Bark</property>
<signal name="clicked" handler="clicked_cb" object="CcAlertChooser" swapped="yes"/>
</object>
</child>
<child>
<object class="CcSoundButton" id="drip_button">
<property name="visible">True</property>
<property name="label" translatable="yes">Drip</property>
<signal name="clicked" handler="clicked_cb" object="CcAlertChooser" swapped="yes"/>
</object>
</child>
<child>
<object class="CcSoundButton" id="glass_button">
<property name="visible">True</property>
<property name="label" translatable="yes">Glass</property>
<signal name="clicked" handler="clicked_cb" object="CcAlertChooser" swapped="yes"/>
</object>
</child>
<child>
<object class="CcSoundButton" id="sonar_button">
<property name="visible">True</property>
<property name="label" translatable="yes">Sonar</property>
<signal name="clicked" handler="clicked_cb" object="CcAlertChooser" swapped="yes"/>
</object>
</child>
</template>
</interface>
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2018 Canonical Ltd.
*
* 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "cc-sound-resources.h"
#include "cc-alert-chooser.h"
struct _CcAlertChooser
{
GtkBox parent_instance;
};
G_DEFINE_TYPE (CcAlertChooser, cc_fade_slider, GTK_TYPE_BOX)
static void
changed_cb (CcAlertChooser *self)
{
gdouble value;
const pa_channel_map *pa_map;
pa_cvolume pa_volume;
if (self->channel_map == NULL)
return;
value = gtk_adjustment_get_value (self->adjustment);
pa_map = gvc_channel_map_get_pa_channel_map (self->channel_map);
pa_volume = *gvc_channel_map_get_cvolume (self->channel_map);
pa_cvolume_set_fade (&pa_volume, pa_map, value);
gvc_channel_map_volume_changed (self->channel_map, &pa_volume, TRUE);
}
static void
volume_changed_cb (CcAlertChooser *self)
{
const gdouble *volumes;
volumes = gvc_channel_map_get_volume (self->channel_map);
g_signal_handlers_block_by_func (self->adjustment, volume_changed_cb, self);
gtk_adjustment_set_value (self->adjustment, volumes[FADE]);
g_signal_handlers_unblock_by_func (self->adjustment, volume_changed_cb, self);
}
static void
cc_fade_slider_dispose (GObject *object)
{
CcAlertChooser *self = CC_ALERT_CHOOSER (object);
g_clear_object (&self->channel_map);
G_OBJECT_CLASS (cc_fade_slider_parent_class)->dispose (object);
}
void
cc_fade_slider_class_init (CcAlertChooserClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
object_class->dispose = cc_fade_slider_dispose;
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/sound/cc-alert-chooser.ui");
gtk_widget_class_bind_template_child (widget_class, CcAlertChooser, adjustment);
gtk_widget_class_bind_template_callback (widget_class, changed_cb);
}
void
cc_fade_slider_init (CcAlertChooser *self)
{
g_resources_register (cc_sound_get_resource ());
gtk_widget_init_template (GTK_WIDGET (self));
}
void
cc_fade_slider_set_channel_map (CcAlertChooser *self,
GvcChannelMap *channel_map)
{
g_return_if_fail (CC_IS_ALERT_CHOOSER (self));
if (self->channel_map != NULL) {
g_signal_handler_disconnect (self->channel_map, self->volume_changed_handler);
self->volume_changed_handler = 0;
}
g_clear_object (&self->channel_map);
if (channel_map != NULL) {
self->channel_map = g_object_ref (channel_map);
self->volume_changed_handler = g_signal_connect_object (channel_map,
"volume-changed",
G_CALLBACK (volume_changed_cb),
self, G_CONNECT_SWAPPED);
volume_changed_cb (self);
}
}
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2018 Canonical Ltd.
*
* 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <gtk/gtk.h>
G_BEGIN_DECLS
#define CC_TYPE_ALERT_CHOOSER (cc_alert_chooser_get_type ())
G_DECLARE_FINAL_TYPE (CcAlertChooser, cc_alert_chooser, CC, ALERT_CHOOSER, GtkBox)
G_END_DECLS
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<!-- interface-requires gtk+ 3.0 -->
<template class="CcAltertSelector" parent="GtkBox">
<property name="homogeneous">True</property>
<child>
<object class="CcSoundButton">
<property name="visible">True</property>
<property name="label" translatable="yes">Bark</property>
</object>
</child>
<child>
<object class="CcSoundButton">
<property name="visible">True</property>
<property name="label" translatable="yes">Drip</property>
</object>
</child>
<child>
<object class="CcSoundButton">
<property name="visible">True</property>
<property name="label" translatable="yes">Glass</property>
</object>
</child>
<child>
<object class="CcSoundButton">
<property name="visible">True</property>
<property name="label" translatable="yes">Sonar</property>
</object>
</child>
</template>
</interface>
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2018 Canonical Ltd.
*
* 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "cc-sound-resources.h"
#include "cc-balance-slider.h"
#include "gvc-channel-map-private.h"
struct _CcBalanceSlider
{
GtkBox parent_instance;
GtkAdjustment *adjustment;
GvcChannelMap *channel_map;
guint volume_changed_handler;
};
G_DEFINE_TYPE (CcBalanceSlider, cc_balance_slider, GTK_TYPE_BOX)
static void
changed_cb (CcBalanceSlider *self)
{
gdouble value;
const pa_channel_map *pa_map;
pa_cvolume pa_volume;
if (self->channel_map == NULL)
return;
value = gtk_adjustment_get_value (self->adjustment);
pa_map = gvc_channel_map_get_pa_channel_map (self->channel_map);
pa_volume = *gvc_channel_map_get_cvolume (self->channel_map);
pa_cvolume_set_balance (&pa_volume, pa_map, value);
gvc_channel_map_volume_changed (self->channel_map, &pa_volume, TRUE);
}
static void
volume_changed_cb (CcBalanceSlider *self)
{
const gdouble *volumes;
volumes = gvc_channel_map_get_volume (self->channel_map);
g_signal_handlers_block_by_func (self->adjustment, volume_changed_cb, self);
gtk_adjustment_set_value (self->adjustment, volumes[BALANCE]);
g_signal_handlers_unblock_by_func (self->adjustment, volume_changed_cb, self);
}
static void
cc_balance_slider_dispose (GObject *object)
{
CcBalanceSlider *self = CC_BALANCE_SLIDER (object);
g_clear_object (&self->channel_map);
G_OBJECT_CLASS (cc_balance_slider_parent_class)->dispose (object);
}
void
cc_balance_slider_class_init (CcBalanceSliderClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
object_class->dispose = cc_balance_slider_dispose;
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/sound/cc-balance-slider.ui");
gtk_widget_class_bind_template_child (widget_class, CcBalanceSlider, adjustment);
gtk_widget_class_bind_template_callback (widget_class, changed_cb);
}
void
cc_balance_slider_init (CcBalanceSlider *self)
{
g_resources_register (cc_sound_get_resource ());
gtk_widget_init_template (GTK_WIDGET (self));
}
void
cc_balance_slider_set_channel_map (CcBalanceSlider *self,
GvcChannelMap *channel_map)
{
g_return_if_fail (CC_IS_BALANCE_SLIDER (self));
if (self->channel_map != NULL) {
g_signal_handler_disconnect (self->channel_map, self->volume_changed_handler);
self->volume_changed_handler = 0;
}
g_clear_object (&self->channel_map);
if (channel_map != NULL) {
self->channel_map = g_object_ref (channel_map);
self->volume_changed_handler = g_signal_connect_object (channel_map,
"volume-changed",
G_CALLBACK (volume_changed_cb),
self, G_CONNECT_SWAPPED);
volume_changed_cb (self);
}
}
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2008 Red Hat, Inc.
* Copyright (C) 2018 Canonical Ltd.
*
* 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 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.
* 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef __GVC_SOUND_THEME_CHOOSER_H
#define __GVC_SOUND_THEME_CHOOSER_H
#pragma once