gnome-control-center r8802 - in trunk: . capplets/appearance capplets/common capplets/sound
- From: hadess svn gnome org
- To: svn-commits-list gnome org
- Subject: gnome-control-center r8802 - in trunk: . capplets/appearance capplets/common capplets/sound
- Date: Sun, 27 Jul 2008 23:32:35 +0000 (UTC)
Author: hadess
Date: Sun Jul 27 23:32:35 2008
New Revision: 8802
URL: http://svn.gnome.org/viewvc/gnome-control-center?rev=8802&view=rev
Log:
2008-07-28 Bastien Nocera <hadess hadess net>
* Makefile.am:
* configure.in: Remove libsounds and esound usage, check for
libcanberra instead (Closes: #542979)
2008-07-28 Bastien Nocera <hadess hadess net>
* theme-util.c:
* theme-util.h: Remove the directory deletion helpers, and
move them to the common sub-directory
2008-07-28 Bastien Nocera <hadess hadess net>
* Makefile.am:
* capplet-util.c (directory_delete_recursive),
(capplet_file_delete_recursive):
* capplet-util.h: Move directory deletion helper function
from the appearance capplet into a common directory
2008-07-28 Bastien Nocera <hadess hadess net>
* Makefile.am:
* sound-properties-capplet.c (create_dialog), (setup_dialog),
(get_legacy_settings):
* sound-properties.glade:
* sound-theme-definition.h:
* sound-theme-file-utils.[ch]:
* sound-theme.[ch]: Remove separate bell settings tab, remove
libsounds dependency, add freedesktop sound theme support through
libcanberra (Closes: #542979)
Added:
trunk/capplets/sound/sound-theme-definition.h
trunk/capplets/sound/sound-theme-file-utils.c
trunk/capplets/sound/sound-theme-file-utils.h
trunk/capplets/sound/sound-theme.c
trunk/capplets/sound/sound-theme.h
Modified:
trunk/ChangeLog
trunk/capplets/appearance/ChangeLog
trunk/capplets/appearance/theme-util.c
trunk/capplets/appearance/theme-util.h
trunk/capplets/common/ChangeLog
trunk/capplets/common/Makefile.am
trunk/capplets/common/capplet-util.c
trunk/capplets/common/capplet-util.h
trunk/capplets/sound/ChangeLog
trunk/capplets/sound/Makefile.am
trunk/capplets/sound/sound-properties-capplet.c
trunk/capplets/sound/sound-properties.glade
Modified: trunk/capplets/appearance/theme-util.c
==============================================================================
--- trunk/capplets/appearance/theme-util.c (original)
+++ trunk/capplets/appearance/theme-util.c Sun Jul 27 23:32:35 2008
@@ -28,67 +28,6 @@
#include "theme-util.h"
-static gboolean
-directory_delete_recursive (GFile *directory, GError **error)
-{
- GFileEnumerator *enumerator;
- GFileInfo *info;
- gboolean success = TRUE;
-
- enumerator = g_file_enumerate_children (directory,
- G_FILE_ATTRIBUTE_STANDARD_NAME ","
- G_FILE_ATTRIBUTE_STANDARD_TYPE,
- G_FILE_QUERY_INFO_NONE,
- NULL, error);
- if (enumerator == NULL)
- return FALSE;
-
- while (success &&
- (info = g_file_enumerator_next_file (enumerator, NULL, NULL))) {
- GFile *child;
-
- child = g_file_get_child (directory, g_file_info_get_name (info));
-
- if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY) {
- success = directory_delete_recursive (child, error);
- }
- g_object_unref (info);
-
- if (success)
- success = g_file_delete (child, NULL, error);
- }
- g_file_enumerator_close (enumerator, NULL, NULL);
-
- if (success)
- success = g_file_delete (directory, NULL, error);
-
- return success;
-}
-
-gboolean
-file_delete_recursive (GFile *file, GError **error)
-{
- GFileInfo *info;
- GFileType type;
-
- g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
-
- info = g_file_query_info (file,
- G_FILE_ATTRIBUTE_STANDARD_TYPE,
- G_FILE_QUERY_INFO_NONE,
- NULL, error);
- if (info == NULL)
- return FALSE;
-
- type = g_file_info_get_file_type (info);
- g_object_unref (info);
-
- if (type == G_FILE_TYPE_DIRECTORY)
- return directory_delete_recursive (file, error);
- else
- return g_file_delete (file, NULL, error);
-}
-
gboolean
theme_is_writable (const gpointer theme)
{
Modified: trunk/capplets/appearance/theme-util.h
==============================================================================
--- trunk/capplets/appearance/theme-util.h (original)
+++ trunk/capplets/appearance/theme-util.h Sun Jul 27 23:32:35 2008
@@ -61,4 +61,4 @@
void theme_install_file (GtkWindow *parent, const gchar *path);
gboolean packagekit_available (void);
-gboolean file_delete_recursive (GFile *directory, GError **error);
+
Modified: trunk/capplets/common/Makefile.am
==============================================================================
--- trunk/capplets/common/Makefile.am (original)
+++ trunk/capplets/common/Makefile.am Sun Jul 27 23:32:35 2008
@@ -11,7 +11,8 @@
$(DBUS_CFLAGS) \
$(GNOME_DESKTOP_CFLAGS) \
$(METACITY_CFLAGS) \
- $(GSD_DBUS_CFLAGS)
+ $(GSD_DBUS_CFLAGS) \
+ $(GIO_CFLAGS)
noinst_LTLIBRARIES = libcommon.la
@@ -42,9 +43,10 @@
libcommon_la_LIBADD = \
$(top_builddir)/libwindow-settings/libgnome-window-settings.la \
- $(METACITY_LIBS) \
+ $(METACITY_LIBS) \
$(DBUS_LIBS) \
- $(GNOME_DESKTOP_LIBS)
+ $(GNOME_DESKTOP_LIBS) \
+ $(GIO_LIBS)
gnome_theme_test_SOURCES = \
gnome-theme-test.c
@@ -54,4 +56,4 @@
$(GNOMECC_CAPPLETS_LIBS)
noinst_PROGRAMS = \
- gnome-theme-test
\ No newline at end of file
+ gnome-theme-test
Modified: trunk/capplets/common/capplet-util.c
==============================================================================
--- trunk/capplets/common/capplet-util.c (original)
+++ trunk/capplets/common/capplet-util.c Sun Jul 27 23:32:35 2008
@@ -96,3 +96,73 @@
gtk_window_set_default_icon_name (icon_file_name);
gtk_window_set_icon_name (GTK_WINDOW (window), icon_file_name);
}
+
+static gboolean
+directory_delete_recursive (GFile *directory, GError **error)
+{
+ GFileEnumerator *enumerator;
+ GFileInfo *info;
+ gboolean success = TRUE;
+
+ enumerator = g_file_enumerate_children (directory,
+ G_FILE_ATTRIBUTE_STANDARD_NAME ","
+ G_FILE_ATTRIBUTE_STANDARD_TYPE,
+ G_FILE_QUERY_INFO_NONE,
+ NULL, error);
+ if (enumerator == NULL)
+ return FALSE;
+
+ while (success &&
+ (info = g_file_enumerator_next_file (enumerator, NULL, NULL))) {
+ GFile *child;
+
+ child = g_file_get_child (directory, g_file_info_get_name (info));
+
+ if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY) {
+ success = directory_delete_recursive (child, error);
+ }
+ g_object_unref (info);
+
+ if (success)
+ success = g_file_delete (child, NULL, error);
+ }
+ g_file_enumerator_close (enumerator, NULL, NULL);
+
+ if (success)
+ success = g_file_delete (directory, NULL, error);
+
+ return success;
+}
+
+/**
+ * capplet_file_delete_recursive :
+ * @file :
+ * @error :
+ *
+ * A utility routine to delete files and/or directories,
+ * including non-empty directories.
+ **/
+gboolean
+capplet_file_delete_recursive (GFile *file, GError **error)
+{
+ GFileInfo *info;
+ GFileType type;
+
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+ info = g_file_query_info (file,
+ G_FILE_ATTRIBUTE_STANDARD_TYPE,
+ G_FILE_QUERY_INFO_NONE,
+ NULL, error);
+ if (info == NULL)
+ return FALSE;
+
+ type = g_file_info_get_file_type (info);
+ g_object_unref (info);
+
+ if (type == G_FILE_TYPE_DIRECTORY)
+ return directory_delete_recursive (file, error);
+ else
+ return g_file_delete (file, NULL, error);
+}
+
Modified: trunk/capplets/common/capplet-util.h
==============================================================================
--- trunk/capplets/common/capplet-util.h (original)
+++ trunk/capplets/common/capplet-util.h Sun Jul 27 23:32:35 2008
@@ -24,6 +24,7 @@
#ifndef __CAPPLET_UTIL_H
#define __CAPPLET_UTIL_H
+#include <gio/gio.h>
#include <gnome.h>
#include <gconf/gconf.h>
#include <gconf/gconf-changeset.h>
@@ -46,5 +47,6 @@
void capplet_help (GtkWindow *parent, char const *helpfile, char const *section);
void capplet_set_icon (GtkWidget *window, char const *icon_file_name);
+gboolean capplet_file_delete_recursive (GFile *directory, GError **error);
#endif /* __CAPPLET_UTIL_H */
Modified: trunk/capplets/sound/Makefile.am
==============================================================================
--- trunk/capplets/sound/Makefile.am (original)
+++ trunk/capplets/sound/Makefile.am Sun Jul 27 23:32:35 2008
@@ -4,15 +4,23 @@
bin_PROGRAMS = gnome-sound-properties
gnome_sound_properties_LDADD = \
- $(top_builddir)/libsounds/libsounds.la \
$(GNOMECC_CAPPLETS_LIBS) \
- $(SOUND_CAPPLET_LIBS) \
+ $(CANBERRA_LIBS) $(SOUND_CAPPLET_LIBS) \
$(HAL_LIBS)
-gnome_sound_properties_SOURCES = sound-properties-capplet.c pipeline-tests.h pipeline-tests.c mixer-support.h mixer-support.c
+gnome_sound_properties_SOURCES = \
+ sound-properties-capplet.c \
+ pipeline-tests.h \
+ pipeline-tests.c \
+ mixer-support.h \
+ mixer-support.c \
+ sound-theme.c \
+ sound-theme.h \
+ sound-theme-file-utils.c \
+ sound-theme-file-utils.h
INCLUDES = \
$(GNOMECC_CAPPLETS_CFLAGS) \
- $(SOUND_CAPPLET_CFLAGS) \
+ $(CANBERRA_CFLAGS) $(SOUND_CAPPLET_CFLAGS) \
$(HAL_CFLAGS) \
-DGNOMELOCALEDIR="\"$(datadir)/locale\"" \
-DGNOMECC_DATA_DIR="\"$(pkgdatadir)\"" \
Modified: trunk/capplets/sound/sound-properties-capplet.c
==============================================================================
--- trunk/capplets/sound/sound-properties-capplet.c (original)
+++ trunk/capplets/sound/sound-properties-capplet.c Sun Jul 27 23:32:35 2008
@@ -35,7 +35,6 @@
#include "capplet-util.h"
#include "gconf-property-editor.h"
-#include "libsounds/sound-view.h"
#include <glade/glade.h>
@@ -53,8 +52,8 @@
#include "activate-settings-daemon.h"
#include "pipeline-tests.h"
-
#include "mixer-support.h"
+#include "sound-theme.h"
typedef enum {
AUDIO_PLAYBACK,
@@ -72,13 +71,11 @@
const gchar *test_pipeline;
} DeviceChooser;
-#define ENABLE_ESD_KEY "/desktop/gnome/sound/enable_esd"
#define EVENT_SOUNDS_KEY "/desktop/gnome/sound/event_sounds"
+#define INPUT_SOUNDS_KEY "/desktop/gnome/sound/input_feedback_sounds"
#define DEFAULT_MIXER_DEVICE_KEY "/desktop/gnome/sound/default_mixer_device"
#define DEFAULT_MIXER_TRACKS_KEY "/desktop/gnome/sound/default_mixer_tracks"
-#define VISUAL_BELL_KEY "/apps/metacity/general/visual_bell"
#define AUDIO_BELL_KEY "/apps/metacity/general/audible_bell"
-#define VISUAL_BELL_TYPE_KEY "/apps/metacity/general/visual_bell_type"
#define GST_GCONF_DIR "/system/gstreamer/0.10"
#define AUDIO_TEST_SOURCE "audiotestsrc wave=sine freq=512"
@@ -88,7 +85,6 @@
/* Capplet-specific prototypes */
-static SoundProperties *props = NULL;
static GConfClient *gconf_client = NULL;
static GtkWidget *dialog_win = NULL;
static GList *device_choosers = NULL;
@@ -111,78 +107,18 @@
return have_xkb;
}
-static void
-props_changed_cb (SoundProperties *p, SoundEvent *event, gpointer data)
-{
- sound_properties_user_save (p);
-}
-
-
-
-static GConfEnumStringPair bell_flash_enums[] = {
- { 0, "frame_flash" },
- { 1, "fullscreen" },
- { -1, NULL }
-};
-
-static GConfValue *
-bell_flash_from_widget (GConfPropertyEditor *peditor, const GConfValue *value)
-{
- GConfValue *new_value;
-
- new_value = gconf_value_new (GCONF_VALUE_STRING);
- gconf_value_set_string (new_value,
- gconf_enum_to_string (bell_flash_enums, gconf_value_get_int (value)));
-
- return new_value;
-}
-
-static GConfValue *
-bell_flash_to_widget (GConfPropertyEditor *peditor, const GConfValue *value)
-{
- GConfValue *new_value;
- const gchar *str;
- gint val = 2;
-
- str = (value && (value->type == GCONF_VALUE_STRING)) ? gconf_value_get_string (value) : NULL;
-
- new_value = gconf_value_new (GCONF_VALUE_INT);
- if (value->type == GCONF_VALUE_STRING) {
- gconf_string_to_enum (bell_flash_enums,
- str,
- &val);
- }
- gconf_value_set_int (new_value, val);
-
- return new_value;
-}
-
static GladeXML *
create_dialog (void)
{
GladeXML *dialog;
- GtkWidget *widget, *box, *view, *image;
-
- dialog = glade_xml_new (GNOMECC_GLADE_DIR "/sound-properties.glade", "sound_prefs_dialog", NULL);
- if (dialog == NULL)
- return NULL;
-
- widget = glade_xml_get_widget (dialog, "sound_prefs_dialog");
-
- props = sound_properties_new ();
- sound_properties_add_defaults (props, NULL);
- g_signal_connect (G_OBJECT (props), "event_changed",
- (GCallback) props_changed_cb, NULL);
- view = sound_view_new (props);
- box = glade_xml_get_widget (dialog, "events_vbox");
- gtk_box_pack_start (GTK_BOX (box), view, TRUE, TRUE, 0);
- gtk_widget_show_all (view);
-
- g_signal_connect_swapped (G_OBJECT (widget), "destroy",
- (GCallback) gtk_object_destroy, props);
+ GtkWidget *image;
- gtk_image_set_from_file (GTK_IMAGE (WID ("bell_image")),
- GNOMECC_DATA_DIR "/pixmaps/visual-bell.png");
+ dialog = glade_xml_new ("sound-properties.glade", "sound_prefs_dialog", NULL);
+ if (dialog == NULL) {
+ dialog = glade_xml_new (GNOMECC_GLADE_DIR "/sound-properties.glade", "sound_prefs_dialog", NULL);
+ if (dialog == NULL)
+ return NULL;
+ }
image = gtk_image_new_from_stock (GTK_STOCK_APPLY, GTK_ICON_SIZE_BUTTON);
gtk_button_set_image (GTK_BUTTON (WID ("sounds_playback_test")), image);
@@ -196,10 +132,6 @@
image = gtk_image_new_from_stock (GTK_STOCK_APPLY, GTK_ICON_SIZE_BUTTON);
gtk_button_set_image (GTK_BUTTON (WID ("chat_audio_capture_test")), image);
- if (!CheckXKB()) {
- gtk_widget_set_sensitive (WID ("bell_flash_alignment"), FALSE);
- }
-
return dialog;
}
@@ -1082,29 +1014,16 @@
WID ("chat_audio_capture_test"),
"gconfaudiosrc" AUDIO_TEST_IN_BETWEEN "gconfaudiosink profile=chat");
-#ifdef HAVE_ESD
- peditor = gconf_peditor_new_boolean (NULL, ENABLE_ESD_KEY, WID ("enable_toggle"), NULL);
- gconf_peditor_widget_set_guard (GCONF_PROPERTY_EDITOR (peditor), WID ("events_toggle"));
- gconf_peditor_widget_set_guard (GCONF_PROPERTY_EDITOR (peditor), WID ("events_vbox"));
-#else
- gtk_widget_hide (WID ("enable_toggle"));
-#endif
- gconf_peditor_new_boolean (NULL, EVENT_SOUNDS_KEY, WID ("events_toggle"), NULL);
-
+ peditor = gconf_peditor_new_boolean (NULL, EVENT_SOUNDS_KEY, WID ("events_toggle"), NULL);
+ gconf_peditor_widget_set_guard (GCONF_PROPERTY_EDITOR (peditor), WID ("input_feedback_toggle"));
+ gconf_peditor_widget_set_guard (GCONF_PROPERTY_EDITOR (peditor), WID ("sound_theme_combobox"));
+ gconf_peditor_widget_set_guard (GCONF_PROPERTY_EDITOR (peditor), WID ("sounds_treeview"));
+ gconf_peditor_new_boolean (NULL, INPUT_SOUNDS_KEY, WID ("input_feedback_toggle"), NULL);
gconf_peditor_new_boolean (NULL, AUDIO_BELL_KEY, WID ("bell_audible_toggle"), NULL);
- peditor = gconf_peditor_new_boolean (NULL, VISUAL_BELL_KEY, WID ("bell_visual_toggle"), NULL);
- gconf_peditor_widget_set_guard (GCONF_PROPERTY_EDITOR (peditor), WID ("bell_flash_vbox"));
-
- /* peditor not so convenient for the radiobuttons */
- gconf_peditor_new_select_radio (NULL,
- VISUAL_BELL_TYPE_KEY,
- gtk_radio_button_get_group (GTK_RADIO_BUTTON (WID ("bell_flash_window_radio"))),
- "conv-to-widget-cb", bell_flash_to_widget,
- "conv-from-widget-cb", bell_flash_from_widget,
- NULL);
-
setup_default_mixer (dialog);
+ setup_sound_theme (dialog);
+ setup_sound_theme_custom (dialog, CheckXKB());
}
/* get_legacy_settings
@@ -1123,7 +1042,6 @@
gboolean val_bool, def;
client = gconf_client_get_default ();
- COPY_FROM_LEGACY (bool, "/desktop/gnome/sound/enable_esd", "/sound/system/settings/start_esd=false");
COPY_FROM_LEGACY (bool, "/desktop/gnome/sound/event_sounds", "/sound/system/settings/event_sounds=false");
g_object_unref (G_OBJECT (client));
}
Modified: trunk/capplets/sound/sound-properties.glade
==============================================================================
--- trunk/capplets/sound/sound-properties.glade (original)
+++ trunk/capplets/sound/sound-properties.glade Sun Jul 27 23:32:35 2008
@@ -211,7 +211,7 @@
<property name="enable_popup">False</property>
<child>
- <widget class="GtkVBox" id="vbox13">
+ <widget class="GtkVBox" id="devices_vbox">
<property name="border_width">12</property>
<property name="visible">True</property>
<property name="homogeneous">False</property>
@@ -940,33 +940,13 @@
</child>
<child>
- <widget class="GtkVBox" id="vbox1">
+ <widget class="GtkVBox" id="sounds_vbox">
<property name="border_width">12</property>
<property name="visible">True</property>
<property name="homogeneous">False</property>
<property name="spacing">6</property>
<child>
- <widget class="GtkCheckButton" id="enable_toggle">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">E_nable software sound mixing</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="active">False</property>
- <property name="inconsistent">False</property>
- <property name="draw_indicator">True</property>
- <signal name="toggled" handler="enable_toggled_cb"/>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
<widget class="GtkCheckButton" id="events_toggle">
<property name="visible">True</property>
<property name="can_focus">True</property>
@@ -987,110 +967,32 @@
</child>
<child>
- <widget class="GtkAlignment" id="alignment4">
+ <widget class="GtkAlignment" id="alignment17">
<property name="visible">True</property>
- <property name="xalign">0</property>
- <property name="yalign">0</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
<property name="xscale">1</property>
<property name="yscale">1</property>
- <property name="top_padding">12</property>
+ <property name="top_padding">0</property>
<property name="bottom_padding">0</property>
- <property name="left_padding">0</property>
+ <property name="left_padding">12</property>
<property name="right_padding">0</property>
<child>
- <widget class="GtkVBox" id="events_vbox">
+ <widget class="GtkVBox" id="vbox18">
<property name="visible">True</property>
<property name="homogeneous">False</property>
<property name="spacing">0</property>
<child>
- <placeholder/>
- </child>
- </widget>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="tab_expand">False</property>
- <property name="tab_fill">True</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label1">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Sounds</property>
- <property name="use_underline">True</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_CENTER</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0</property>
- <property name="yalign">0</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
- <property name="width_chars">-1</property>
- <property name="single_line_mode">False</property>
- <property name="angle">0</property>
- </widget>
- <packing>
- <property name="type">tab</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkVBox" id="sound_events_vbox">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">0</property>
-
- <child>
- <widget class="GtkHBox" id="hbox2">
- <property name="border_width">12</property>
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">12</property>
-
- <child>
- <widget class="GtkImage" id="bell_image">
- <property name="visible">True</property>
- <property name="stock">gtk-missing-image</property>
- <property name="icon_size">4</property>
- <property name="xalign">0</property>
- <property name="yalign">0</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">True</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkVBox" id="bell_box">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">6</property>
-
- <child>
- <widget class="GtkCheckButton" id="bell_audible_toggle">
+ <widget class="GtkCheckButton" id="input_feedback_toggle">
<property name="visible">True</property>
<property name="can_focus">True</property>
- <property name="label" translatable="yes">_Enable system beep</property>
+ <property name="label" translatable="yes">Play sounds when buttons are pressed</property>
<property name="use_underline">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">True</property>
- <property name="active">True</property>
+ <property name="active">False</property>
<property name="inconsistent">False</property>
<property name="draw_indicator">True</property>
</widget>
@@ -1102,10 +1004,10 @@
</child>
<child>
- <widget class="GtkCheckButton" id="bell_visual_toggle">
+ <widget class="GtkCheckButton" id="bell_audible_toggle">
<property name="visible">True</property>
<property name="can_focus">True</property>
- <property name="label" translatable="yes">_Visual system beep</property>
+ <property name="label" translatable="yes">_Play system beep sound</property>
<property name="use_underline">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">True</property>
@@ -1119,77 +1021,141 @@
<property name="fill">False</property>
</packing>
</child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkFrame" id="frame1">
+ <property name="visible">True</property>
+ <property name="label_xalign">0</property>
+ <property name="label_yalign">0.5</property>
+ <property name="shadow_type">GTK_SHADOW_NONE</property>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment15">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">1</property>
+ <property name="yscale">1</property>
+ <property name="top_padding">12</property>
+ <property name="bottom_padding">12</property>
+ <property name="left_padding">12</property>
+ <property name="right_padding">0</property>
<child>
- <widget class="GtkAlignment" id="bell_flash_alignment">
+ <widget class="GtkComboBox" id="sound_theme_combobox">
<property name="visible">True</property>
- <property name="xalign">0</property>
- <property name="yalign">0</property>
- <property name="xscale">1</property>
- <property name="yscale">1</property>
- <property name="top_padding">0</property>
- <property name="bottom_padding">0</property>
- <property name="left_padding">12</property>
- <property name="right_padding">0</property>
+ <property name="add_tearoffs">False</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
- <child>
- <widget class="GtkVBox" id="bell_flash_vbox">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">6</property>
+ <child>
+ <widget class="GtkLabel" id="label17">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes"><b>Sound theme</b></property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="type">label_item</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
- <child>
- <widget class="GtkRadioButton" id="bell_flash_window_radio">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Flash _window titlebar</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="active">False</property>
- <property name="inconsistent">False</property>
- <property name="draw_indicator">True</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
+ <child>
+ <widget class="GtkFrame" id="frame2">
+ <property name="visible">True</property>
+ <property name="label_xalign">0</property>
+ <property name="label_yalign">0.5</property>
+ <property name="shadow_type">GTK_SHADOW_NONE</property>
- <child>
- <widget class="GtkRadioButton" id="bell_flash_screen_radio">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Flash _entire screen</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="active">False</property>
- <property name="inconsistent">False</property>
- <property name="draw_indicator">True</property>
- <property name="group">bell_flash_window_radio</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
+ <child>
+ <widget class="GtkAlignment" id="alignment16">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">1</property>
+ <property name="yscale">1</property>
+ <property name="top_padding">12</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">12</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow2">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
+ <property name="vscrollbar_policy">GTK_POLICY_ALWAYS</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+ <child>
+ <widget class="GtkTreeView" id="sounds_treeview">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="headers_visible">True</property>
+ <property name="rules_hint">False</property>
+ <property name="reorderable">False</property>
+ <property name="enable_search">True</property>
+ <property name="fixed_height_mode">False</property>
+ <property name="hover_selection">False</property>
+ <property name="hover_expand">False</property>
</widget>
</child>
</widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
</child>
</widget>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label18">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes"><b>System sounds</b></property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
<packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
+ <property name="type">label_item</property>
</packing>
</child>
</widget>
@@ -1207,12 +1173,12 @@
</child>
<child>
- <widget class="GtkLabel" id="label4">
+ <widget class="GtkLabel" id="label1">
<property name="visible">True</property>
- <property name="label" translatable="yes">System Beep</property>
- <property name="use_underline">False</property>
+ <property name="label" translatable="yes">Sounds</property>
+ <property name="use_underline">True</property>
<property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
<property name="wrap">False</property>
<property name="selectable">False</property>
<property name="xalign">0</property>
Added: trunk/capplets/sound/sound-theme-definition.h
==============================================================================
--- (empty file)
+++ trunk/capplets/sound/sound-theme-definition.h Sun Jul 27 23:32:35 2008
@@ -0,0 +1,71 @@
+/* -*- mode: c; style: linux -*- */
+/* -*- c-basic-offset: 2 -*- */
+
+/* sound-theme-definition.h
+ * Copyright (C) 2008 Bastien Nocera <hadess hadess net>
+ *
+ * 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, 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.
+ */
+
+typedef enum {
+ CATEGORY_INVALID,
+ CATEGORY_BELL,
+ CATEGORY_WINDOWS_BUTTONS,
+ CATEGORY_DESKTOP,
+ CATEGORY_ALERTS,
+ NUM_CATEGORIES
+} CategoryType;
+
+typedef enum {
+ SOUND_TYPE_NORMAL,
+ SOUND_TYPE_AUDIO_BELL,
+ SOUND_TYPE_VISUAL_BELL,
+ SOUND_TYPE_FEEDBACK
+} SoundType;
+
+static struct {
+ CategoryType category;
+ SoundType type;
+ const char *display_name;
+ const char *names[6];
+} sounds[20] = {
+ /* Bell */
+ { CATEGORY_BELL, SOUND_TYPE_AUDIO_BELL, N_("Audible bell"), { "bell-terminal", "bell-window-system", NULL } },
+ { CATEGORY_BELL, SOUND_TYPE_VISUAL_BELL, N_("Visual bell"), { NULL } },
+ /* Windows and buttons */
+ { CATEGORY_WINDOWS_BUTTONS, -1, N_("Windows and Buttons"), { NULL } },
+ { CATEGORY_WINDOWS_BUTTONS, SOUND_TYPE_FEEDBACK, N_("Button clicked"), { "button-pressed", "menu-click", "menu-popup", "menu-popdown", "menu-replace", NULL } },
+ { CATEGORY_WINDOWS_BUTTONS, SOUND_TYPE_FEEDBACK, N_("Button toggled"), { "button-toggle-off", "button-toggle-on", NULL } },
+ { CATEGORY_WINDOWS_BUTTONS, SOUND_TYPE_FEEDBACK, N_("Window maximized"), { "window-maximized", NULL } },
+ { CATEGORY_WINDOWS_BUTTONS, SOUND_TYPE_FEEDBACK, N_("Window unmaximized"), { "window-unmaximized", NULL } },
+ { CATEGORY_WINDOWS_BUTTONS, SOUND_TYPE_FEEDBACK, N_("Window minimised"), { "window-minimized", NULL } },
+ /* Desktop */
+ { CATEGORY_DESKTOP, -1, N_("Desktop"), { NULL } },
+ { CATEGORY_DESKTOP, SOUND_TYPE_NORMAL, N_("Login"), { "desktop-login", NULL } },
+ { CATEGORY_DESKTOP, SOUND_TYPE_NORMAL, N_("Logout"), { "desktop-logout", NULL } },
+ { CATEGORY_DESKTOP, SOUND_TYPE_NORMAL, N_("New e-mail"), { "message-new-email", NULL } },
+ { CATEGORY_DESKTOP, SOUND_TYPE_NORMAL, N_("Empty Trash"), { "trash-empty", NULL } },
+ { CATEGORY_DESKTOP, SOUND_TYPE_NORMAL, N_("Long action completed (download, CD burning, etc.)"), { "complete-copy", "complete-download", "complete-media-burn", "complete-media-rip", "complete-scan", NULL } },
+ /* Alerts? */
+ { CATEGORY_ALERTS, -1, N_("Alerts"), { NULL } },
+ { CATEGORY_ALERTS, SOUND_TYPE_NORMAL, N_("Information or Question"), { "dialog-information", "dialog-question", NULL } },
+ { CATEGORY_ALERTS, SOUND_TYPE_NORMAL, N_("Warning"), { "dialog-warning", NULL } },
+ { CATEGORY_ALERTS, SOUND_TYPE_NORMAL, N_("Error"), { "dialog-error", NULL } },
+ { CATEGORY_ALERTS, SOUND_TYPE_NORMAL, N_("Battery warning"), { "power-unplug-battery-low", "battery-low", "battery-caution", NULL } },
+ /* Finish off */
+ { -1, -1, NULL, { NULL } }
+};
+
Added: trunk/capplets/sound/sound-theme-file-utils.c
==============================================================================
--- (empty file)
+++ trunk/capplets/sound/sound-theme-file-utils.c Sun Jul 27 23:32:35 2008
@@ -0,0 +1,152 @@
+/* -*- mode: c; style: linux -*- */
+/* -*- c-basic-offset: 2 -*- */
+
+/* sound-theme-file-utils.c
+ * Copyright (C) 2008 Bastien Nocera <hadess hadess net>
+ *
+ * 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, 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.
+ */
+
+#include <config.h>
+#include <glib/gstdio.h>
+#include <gio/gio.h>
+
+#include "capplet-util.h"
+
+#define CUSTOM_THEME_NAME "__custom"
+
+char *
+custom_theme_dir_path (const char *child)
+{
+ static char *dir = NULL;
+ const char *data_dir;
+
+ if (dir == NULL) {
+ data_dir = g_get_user_data_dir ();
+ dir = g_build_filename (data_dir, "sounds", CUSTOM_THEME_NAME, NULL);
+ }
+ if (child == NULL)
+ return g_strdup (dir);
+
+ return g_build_filename (dir, child, NULL);
+}
+
+void
+delete_custom_theme_dir (void)
+{
+ char *dir;
+ GFile *file;
+
+ dir = custom_theme_dir_path (NULL);
+ file = g_file_new_for_path (dir);
+ g_free (dir);
+ capplet_file_delete_recursive (file, NULL);
+ g_object_unref (file);
+
+ g_debug ("deleted the custom theme dir");
+}
+
+static void
+delete_one_file (const char *sound_name, const char *pattern)
+{
+ GFile *file;
+ char *name, *filename;
+
+ name = g_strdup_printf (pattern, sound_name);
+ filename = custom_theme_dir_path (name);
+ g_free (name);
+ file = g_file_new_for_path (filename);
+ g_free (filename);
+ capplet_file_delete_recursive (file, NULL);
+ g_object_unref (file);
+}
+
+void
+delete_old_files (char **sounds)
+{
+ guint i;
+
+ for (i = 0; sounds[i] != NULL; i++) {
+ delete_one_file (sounds[i], "%s.ogg");
+ }
+}
+
+void
+delete_disabled_files (char **sounds)
+{
+ guint i;
+
+ for (i = 0; sounds[i] != NULL; i++)
+ delete_one_file (sounds[i], "%s.disabled");
+}
+
+static void
+create_one_file (GFile *file)
+{
+ GFileOutputStream* stream;
+
+ stream = g_file_create (file, G_FILE_CREATE_NONE, NULL, NULL);
+ if (stream != NULL) {
+ g_output_stream_close (G_OUTPUT_STREAM (stream), NULL, NULL);
+ g_object_unref (stream);
+ }
+}
+
+void
+add_disabled_file (char **sounds)
+{
+ guint i;
+
+ for (i = 0; sounds[i] != NULL; i++) {
+ GFile *file;
+ char *name, *filename;
+
+ name = g_strdup_printf ("%s.disabled", sounds[i]);
+ filename = custom_theme_dir_path (name);
+ g_free (name);
+ file = g_file_new_for_path (filename);
+ g_free (filename);
+
+ create_one_file (file);
+ g_object_unref (file);
+ }
+}
+
+void
+add_custom_file (char **sounds, const char *filename)
+{
+ guint i;
+
+ for (i = 0; sounds[i] != NULL; i++) {
+ GFile *file;
+ char *name, *path;
+
+ /* We use *.ogg because it's the first type of file that
+ * libcanberra looks at */
+ name = g_strdup_printf ("%s.ogg", sounds[i]);
+ path = custom_theme_dir_path (name);
+ g_free (name);
+ /* In case there's already a link there, delete it */
+ g_unlink (path);
+ file = g_file_new_for_path (path);
+ g_free (path);
+
+ /* Create the link */
+ g_file_make_symbolic_link (file, filename, NULL, NULL);
+ g_object_unref (file);
+ }
+}
+
Added: trunk/capplets/sound/sound-theme-file-utils.h
==============================================================================
--- (empty file)
+++ trunk/capplets/sound/sound-theme-file-utils.h Sun Jul 27 23:32:35 2008
@@ -0,0 +1,36 @@
+/* -*- mode: c; style: linux -*- */
+/* -*- c-basic-offset: 2 -*- */
+
+/* sound-theme-file-utils.h
+ * Copyright (C) 2008 Bastien Nocera <hadess hadess net>
+ *
+ * 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, 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.
+ */
+#ifndef __SOUND_THEME_FILE_UTILSHH__
+#define __SOUND_THEME_HH__
+
+#include <gio/gio.h>
+
+char *custom_theme_dir_path (const char *child);
+
+void delete_custom_theme_dir (void);
+void delete_old_files (char **sounds);
+void delete_disabled_files (char **sounds);
+
+void add_disabled_file (char **sounds);
+void add_custom_file (char **sounds, const char *filename);
+
+#endif /* __SOUND_THEME_FILE_UTILS_HH__ */
Added: trunk/capplets/sound/sound-theme.c
==============================================================================
--- (empty file)
+++ trunk/capplets/sound/sound-theme.c Sun Jul 27 23:32:35 2008
@@ -0,0 +1,1135 @@
+/* -*- mode: c; style: linux -*- */
+/* -*- c-basic-offset: 2 -*- */
+
+/* sound-theme.c
+ * Copyright (C) 2008 Bastien Nocera <hadess hadess net>
+ *
+ * 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, 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.
+ */
+
+#include <config.h>
+#include <gtk/gtk.h>
+#include <glib/gi18n.h>
+#include <gio/gio.h>
+#include <glade/glade.h>
+#include <gconf/gconf-client.h>
+#include <canberra-gtk.h>
+
+#include "sound-theme.h"
+#include "capplet-util.h"
+#include "sound-theme-definition.h"
+#include "sound-theme-file-utils.h"
+
+#define SOUND_THEME_KEY "/desktop/gnome/sound/theme_name"
+#define INPUT_SOUNDS_KEY "/desktop/gnome/sound/input_feedback_sounds"
+#define VISUAL_BELL_KEY "/apps/metacity/general/visual_bell"
+#define VISUAL_BELL_TYPE_KEY "/apps/metacity/general/visual_bell_type"
+#define AUDIO_BELL_KEY "/apps/metacity/general/audible_bell"
+
+#define CUSTOM_THEME_NAME "__custom"
+#define PREVIEW_BUTTON_XPAD 5
+
+enum {
+ THEME_DISPLAY_COL,
+ THEME_IDENTIFIER_COL,
+ THEME_PARENT_ID_COL,
+ THEME_NUM_COLS
+};
+
+enum {
+ SOUND_UNSET,
+ SOUND_OFF,
+ SOUND_BUILTIN,
+ SOUND_CUSTOM
+};
+
+#define SOUND_VISUAL_BELL_TITLEBAR SOUND_BUILTIN
+#define SOUND_VISUAL_BELL_SCREEN SOUND_CUSTOM
+
+static void set_combox_for_theme_name (GladeXML *dialog, const char *name);
+static gboolean theme_changed_custom_reinit (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data);
+static void dump_theme (GladeXML *dialog);
+
+static int
+visual_bell_gconf_to_setting (GConfClient *client)
+{
+ char *value;
+ int retval;
+
+ if (gconf_client_get_bool (client, VISUAL_BELL_KEY, NULL) == FALSE) {
+ return SOUND_OFF;
+ }
+ value = gconf_client_get_string (client, VISUAL_BELL_TYPE_KEY, NULL);
+ if (value == NULL)
+ return SOUND_VISUAL_BELL_SCREEN;
+ if (strcmp (value, "fullscreen") == 0)
+ retval = SOUND_VISUAL_BELL_SCREEN;
+ else if (strcmp (value, "frame_flash") == 0)
+ retval = SOUND_VISUAL_BELL_TITLEBAR;
+ else
+ retval = SOUND_VISUAL_BELL_SCREEN;
+
+ g_free (value);
+
+ return retval;
+}
+
+static void
+visual_bell_setting_to_gconf (GConfClient *client, int setting)
+{
+ const char *value;
+
+ value = NULL;
+
+ switch (setting) {
+ case SOUND_OFF:
+ break;
+ case SOUND_VISUAL_BELL_SCREEN:
+ value = "fullscreen";
+ break;
+ case SOUND_VISUAL_BELL_TITLEBAR:
+ value = "frame_flash";
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
+ gconf_client_set_string (client, VISUAL_BELL_TYPE_KEY, value ? value : "fullscreen", NULL);
+ gconf_client_set_bool (client, VISUAL_BELL_KEY, value != NULL, NULL);
+}
+
+static void
+theme_changed_cb (GConfClient *client,
+ guint cnxn_id,
+ GConfEntry *entry,
+ GladeXML *dialog)
+{
+ char *theme_name;
+
+ theme_name = gconf_client_get_string (client, SOUND_THEME_KEY, NULL);
+ set_combox_for_theme_name (dialog, theme_name);
+ g_free (theme_name);
+}
+
+static char *
+load_index_theme_name (const char *index, char **parent)
+{
+ GKeyFile *file;
+ char *indexname;
+ gboolean hidden;
+
+ file = g_key_file_new ();
+ if (g_key_file_load_from_file (file, index, G_KEY_FILE_KEEP_TRANSLATIONS, NULL) == FALSE) {
+ g_key_file_free (file);
+ return NULL;
+ }
+ /* Don't add hidden themes to the list */
+ hidden = g_key_file_get_boolean (file, "Sound Theme", "Hidden", NULL);
+ if (hidden != FALSE)
+ return NULL;
+
+ indexname = g_key_file_get_locale_string (file,
+ "Sound Theme",
+ "Name",
+ NULL,
+ NULL);
+
+ /* Save the parent theme, if there's one */
+ if (parent != NULL) {
+ *parent = g_key_file_get_string (file,
+ "Sound Theme",
+ "Inherits",
+ NULL);
+ }
+
+ g_key_file_free (file);
+ return indexname;
+}
+
+static void
+add_theme_to_store (const char *key,
+ const char *value,
+ GtkListStore *store)
+{
+ char *parent;
+
+ parent = NULL;
+
+ /* Get the parent, if we're checking the custom theme */
+ if (strcmp (key, CUSTOM_THEME_NAME) == 0) {
+ char *name, *path;
+
+ path = custom_theme_dir_path ("index.theme");
+ name = load_index_theme_name (path, &parent);
+ g_free (name);
+ g_free (path);
+ }
+ gtk_list_store_insert_with_values (store, NULL, G_MAXINT,
+ THEME_DISPLAY_COL, value,
+ THEME_IDENTIFIER_COL, key,
+ THEME_PARENT_ID_COL, parent,
+ -1);
+ g_free (parent);
+}
+
+static void
+sound_theme_in_dir (GHashTable *hash, const char *dir)
+{
+ GDir *d;
+ const char *name;
+
+ d = g_dir_open (dir, 0, NULL);
+ if (d == NULL)
+ return;
+ while ((name = g_dir_read_name (d)) != NULL) {
+ char *dirname, *index, *indexname;
+
+ /* Look for directories */
+ dirname = g_build_filename (dir, name, NULL);
+ if (g_file_test (dirname, G_FILE_TEST_IS_DIR) == FALSE) {
+ g_free (dirname);
+ continue;
+ }
+
+ /* Look for index files */
+ index = g_build_filename (dirname, "index.theme", NULL);
+ g_free (dirname);
+
+ /* Check the name of the theme in the index.theme file */
+ indexname = load_index_theme_name (index, NULL);
+ g_free (index);
+ if (indexname == NULL)
+ continue;
+
+ g_hash_table_insert (hash, g_strdup (name), indexname);
+ }
+
+ g_dir_close (d);
+}
+
+static void
+set_combox_for_theme_name (GladeXML *dialog, const char *name)
+{
+ GtkTreeIter iter;
+ GtkTreeModel *model;
+ gboolean found;
+
+ g_debug ("setting theme %s", name);
+
+ /* If the name is empty, use "freedesktop" */
+ if (name == NULL || *name == '\0')
+ name = "freedesktop";
+
+ found = FALSE;
+ model = gtk_combo_box_get_model (GTK_COMBO_BOX (WID ("sound_theme_combobox")));
+
+ if (gtk_tree_model_get_iter_first (model, &iter) == FALSE) {
+ return;
+ }
+
+ while (1) {
+ char *value;
+
+ gtk_tree_model_get (model, &iter, THEME_IDENTIFIER_COL, &value, -1);
+ if (value != NULL && strcmp (value, name) == 0) {
+ g_free (value);
+ found = TRUE;
+ break;
+ }
+ if (gtk_tree_model_iter_next (model, &iter) == FALSE)
+ break;
+ }
+
+ /* When we can't find the theme we need to set, try to set the default
+ * one "freedesktop" */
+ if (found == FALSE && strcmp (name, "freedesktop") != 0) {
+ g_debug ("not found, falling back to fdo");
+ set_combox_for_theme_name (dialog, "freedesktop");
+ }
+ else if (found != FALSE)
+ gtk_combo_box_set_active_iter (GTK_COMBO_BOX (WID ("sound_theme_combobox")), &iter);
+}
+
+static void
+theme_combobox_changed (GtkComboBox *widget,
+ GladeXML *dialog)
+{
+ GtkTreeIter iter;
+ GtkTreeModel *model;
+ GConfClient *client;
+ char *theme_name;
+
+ if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (WID ("sound_theme_combobox")), &iter) == FALSE)
+ return;
+
+ model = gtk_combo_box_get_model (GTK_COMBO_BOX (WID ("sound_theme_combobox")));
+ gtk_tree_model_get (model, &iter, THEME_IDENTIFIER_COL, &theme_name, -1);
+
+ client = gconf_client_get_default ();
+ gconf_client_set_string (client, SOUND_THEME_KEY, theme_name, NULL);
+ g_object_unref (G_OBJECT (client));
+
+ /* Don't reinit a custom theme */
+ if (strcmp (theme_name, CUSTOM_THEME_NAME) != 0) {
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (WID ("sounds_treeview")));
+ gtk_tree_model_foreach (model, theme_changed_custom_reinit, NULL);
+
+ /* Delete the custom dir */
+ delete_custom_theme_dir ();
+
+ /* And the combo box entry */
+ model = gtk_combo_box_get_model (GTK_COMBO_BOX (WID ("sound_theme_combobox")));
+ gtk_tree_model_get_iter_first (model, &iter);
+ while (1) {
+ char *parent;
+ gtk_tree_model_get (model, &iter, THEME_PARENT_ID_COL, &parent, -1);
+ if (parent != NULL && strcmp (parent, CUSTOM_THEME_NAME) != 0) {
+ gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
+ g_free (parent);
+ break;
+ }
+ g_free (parent);
+ if (gtk_tree_model_iter_next (model, &iter) == FALSE)
+ break;
+ }
+ }
+}
+
+void
+setup_sound_theme (GladeXML *dialog)
+{
+ GHashTable *hash;
+ GtkListStore *store;
+ GtkCellRenderer *renderer;
+ const char * const *data_dirs;
+ const char *data_dir;
+ char *dir, *theme_name;
+ GConfClient *client;
+ guint i;
+
+ /* Add the theme names and their display name to a hash table,
+ * makes it easy to avoid duplicate themes */
+ hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+
+ data_dirs = g_get_system_data_dirs ();
+ for (i = 0; data_dirs[i] != NULL; i++) {
+ dir = g_build_filename (data_dirs[i], "sounds", NULL);
+ sound_theme_in_dir (hash, dir);
+ g_free (dir);
+ }
+
+ data_dir = g_get_user_data_dir ();
+ dir = g_build_filename (data_dir, "sounds", NULL);
+ sound_theme_in_dir (hash, dir);
+ g_free (dir);
+
+ /* If there isn't at least one theme, make everything
+ * insensitive, LAME! */
+ if (g_hash_table_size (hash) == 0) {
+ gtk_widget_set_sensitive (WID ("sounds_vbox"), FALSE);
+ g_warning ("Bad setup, install the freedesktop sound theme");
+ return;
+ }
+
+ /* Setup the tree model, 3 columns:
+ * - internal theme name/directory
+ * - display theme name
+ * - the internal id for the parent theme, used for the custom theme */
+ store = gtk_list_store_new (THEME_NUM_COLS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
+
+ /* Add the themes to a combobox */
+ g_hash_table_foreach (hash, (GHFunc) add_theme_to_store, store);
+ g_hash_table_destroy (hash);
+
+ /* Set the display */
+ gtk_combo_box_set_model (GTK_COMBO_BOX (WID ("sound_theme_combobox")),
+ GTK_TREE_MODEL (store));
+
+ renderer = gtk_cell_renderer_text_new ();
+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (WID ("sound_theme_combobox")),
+ renderer, TRUE);
+ gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (WID ("sound_theme_combobox")),
+ renderer, "text", THEME_DISPLAY_COL, NULL);
+
+ /* Setup the default as per the GConf setting */
+ client = gconf_client_get_default ();
+ theme_name = gconf_client_get_string (client, SOUND_THEME_KEY, NULL);
+ set_combox_for_theme_name (dialog, theme_name);
+ g_free (theme_name);
+
+ /* Listen for changes in GConf, and on the combobox */
+ gconf_client_notify_add (client, SOUND_THEME_KEY,
+ (GConfClientNotifyFunc) theme_changed_cb, dialog, NULL, NULL);
+ g_object_unref (G_OBJECT (client));
+
+ g_signal_connect (G_OBJECT (WID ("sound_theme_combobox")), "changed",
+ G_CALLBACK (theme_combobox_changed), dialog);
+}
+
+enum {
+ DISPLAY_COL,
+ SETTING_COL,
+ TYPE_COL,
+ SENSITIVE_COL,
+ HAS_PREVIEW_COL,
+ FILENAME_COL,
+ SOUND_NAMES_COL,
+ NUM_COLS
+};
+
+static void
+setting_set_func (GtkTreeViewColumn *tree_column,
+ GtkCellRenderer *cell,
+ GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ int setting;
+ char *filename;
+ SoundType type;
+
+ gtk_tree_model_get (model, iter,
+ SETTING_COL, &setting,
+ FILENAME_COL, &filename,
+ TYPE_COL, &type,
+ -1);
+
+ if (setting == SOUND_UNSET) {
+ g_object_set (cell,
+ "visible", FALSE,
+ NULL);
+ g_free (filename);
+ return;
+ }
+
+ if (type != SOUND_TYPE_VISUAL_BELL) {
+ if (setting == SOUND_OFF) {
+ g_object_set (cell,
+ "text", _("Disabled"),
+ NULL);
+ } else if (setting == SOUND_BUILTIN) {
+ g_object_set (cell,
+ "text", _("Default"),
+ NULL);
+ } else if (setting == SOUND_CUSTOM) {
+ char *display;
+
+ display = g_filename_display_basename (filename);
+ g_object_set (cell,
+ "text", display,
+ NULL);
+ g_free (display);
+ }
+ } else {
+ if (setting == SOUND_OFF) {
+ g_object_set (cell,
+ "text", _("Disabled"),
+ NULL);
+ } else if (setting == SOUND_VISUAL_BELL_SCREEN) {
+ g_object_set (cell,
+ "text", _("Flash screen"),
+ NULL);
+ } else if (setting == SOUND_VISUAL_BELL_TITLEBAR) {
+ g_object_set (cell,
+ "text", _("Flash window"),
+ NULL);
+ }
+ }
+ g_free (filename);
+}
+
+static char *
+get_sound_filename (GladeXML *dialog)
+{
+ GtkWidget *chooser;
+ int response;
+ char *filename, *path;
+ const char * const *data_dirs, *data_dir;
+ GtkFileFilter *filter;
+ guint i;
+
+ chooser = gtk_file_chooser_dialog_new (_("Select Sound File"),
+ GTK_WINDOW (WID("sound_prefs_dialog")),
+ GTK_FILE_CHOOSER_ACTION_OPEN,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
+ NULL);
+
+ gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (chooser), TRUE);
+ gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (chooser), FALSE);
+
+ filter = gtk_file_filter_new ();
+ gtk_file_filter_set_name (filter, _("Sound files"));
+ gtk_file_filter_add_mime_type (filter, "audio/x-vorbis+ogg");
+ gtk_file_filter_add_mime_type (filter, "audio/x-wav");
+ gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (chooser), filter);
+ gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (chooser), filter);
+
+ data_dirs = g_get_system_data_dirs ();
+ for (i = 0; data_dirs[i] != NULL; i++) {
+ path = g_build_filename (data_dirs[i], "sounds", NULL);
+ gtk_file_chooser_add_shortcut_folder (GTK_FILE_CHOOSER (chooser), path, NULL);
+ g_free (path);
+ }
+ data_dir = g_get_user_special_dir (G_USER_DIRECTORY_MUSIC);
+ gtk_file_chooser_add_shortcut_folder (GTK_FILE_CHOOSER (chooser), data_dir, NULL);
+
+ response = gtk_dialog_run (GTK_DIALOG (chooser));
+ filename = NULL;
+ if (response == GTK_RESPONSE_ACCEPT)
+ filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (chooser));
+
+ gtk_widget_destroy (chooser);
+
+ return filename;
+}
+
+static void
+fill_custom_model (GtkListStore *store, const char *prev_filename)
+{
+ GtkTreeIter iter;
+
+ gtk_list_store_clear (store);
+
+ if (prev_filename != NULL) {
+ char *display;
+ display = g_filename_display_basename (prev_filename);
+ gtk_list_store_insert_with_values (store, &iter, G_MAXINT,
+ 0, display,
+ 1, SOUND_CUSTOM,
+ -1);
+ g_free (display);
+ }
+ gtk_list_store_insert_with_values (store, &iter, G_MAXINT,
+ 0, _("Default"),
+ 1, SOUND_BUILTIN,
+ -1);
+ gtk_list_store_insert_with_values (store, &iter, G_MAXINT,
+ 0, _("Disabled"),
+ 1, SOUND_OFF,
+ -1);
+ gtk_list_store_insert_with_values (store, &iter, G_MAXINT,
+ 0, _("Custom..."),
+ 1, SOUND_CUSTOM, -1);
+}
+
+static void
+fill_visual_bell_model (GtkListStore *store)
+{
+ GtkTreeIter iter;
+
+ gtk_list_store_clear (store);
+
+ gtk_list_store_insert_with_values (store, &iter, G_MAXINT,
+ 0, _("Disabled"),
+ 1, SOUND_OFF,
+ -1);
+ gtk_list_store_insert_with_values (store, &iter, G_MAXINT,
+ 0, _("Flash screen"),
+ 1, SOUND_VISUAL_BELL_SCREEN,
+ -1);
+ gtk_list_store_insert_with_values (store, &iter, G_MAXINT,
+ 0, _("Flash window"),
+ 1, SOUND_VISUAL_BELL_TITLEBAR,
+ -1);
+}
+
+static void
+combobox_editing_started (GtkCellRenderer *renderer,
+ GtkCellEditable *editable,
+ gchar *path,
+ GladeXML *dialog)
+{
+ GtkTreeModel *model, *store;
+ GtkTreeIter iter;
+ SoundType type;
+ char *filename;
+
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (WID ("sounds_treeview")));
+ if (gtk_tree_model_get_iter_from_string (model, &iter, path) == FALSE) {
+ return;
+ }
+
+ gtk_tree_model_get (model, &iter, TYPE_COL, &type, FILENAME_COL, &filename, -1);
+ g_object_get (renderer, "model", &store, NULL);
+ if (type == SOUND_TYPE_VISUAL_BELL)
+ fill_visual_bell_model (GTK_LIST_STORE (store));
+ else
+ fill_custom_model (GTK_LIST_STORE (store), filename);
+ g_free (filename);
+}
+
+static gboolean
+save_sounds (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ int type, setting;
+ char *filename, **sounds;
+
+ gtk_tree_model_get (model, iter,
+ TYPE_COL, &type,
+ SETTING_COL, &setting,
+ FILENAME_COL, &filename,
+ SOUND_NAMES_COL, &sounds,
+ -1);
+ if (type == SOUND_TYPE_VISUAL_BELL)
+ return FALSE;
+
+ if (setting == SOUND_BUILTIN) {
+ delete_old_files (sounds);
+ delete_disabled_files (sounds);
+ } else if (setting == SOUND_OFF) {
+ delete_old_files (sounds);
+ add_disabled_file (sounds);
+ } else if (setting == SOUND_CUSTOM) {
+ delete_old_files (sounds);
+ delete_disabled_files (sounds);
+ add_custom_file (sounds, filename);
+ }
+ g_free (filename);
+ g_strfreev (sounds);
+
+ return FALSE;
+}
+
+static void
+save_custom_theme (GtkTreeModel *model, const char *parent)
+{
+ GKeyFile *keyfile;
+ char *data, *path;
+
+ /* Create the custom directory */
+ path = custom_theme_dir_path (NULL);
+ g_mkdir_with_parents (path, 0644);
+ g_free (path);
+
+ /* Save the sounds themselves */
+ gtk_tree_model_foreach (model, (GtkTreeModelForeachFunc) save_sounds, NULL);
+
+ /* Set the data for index.theme */
+ keyfile = g_key_file_new ();
+ g_key_file_set_string (keyfile, "Sound Theme", "Name", _("Custom"));
+ g_key_file_set_string (keyfile, "Sound Theme", "Inherits", parent);
+ g_key_file_set_string (keyfile, "Sound Theme", "Directories", ".");
+ data = g_key_file_to_data (keyfile, NULL, NULL);
+ g_key_file_free (keyfile);
+
+ /* Save the index.theme */
+ path = custom_theme_dir_path ("index.theme");
+ g_file_set_contents (path, data, -1, NULL);
+ g_free (path);
+ g_free (data);
+}
+
+static gboolean
+count_customised_sounds (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ int *num_custom)
+{
+ int type, setting;
+
+ gtk_tree_model_get (model, iter, TYPE_COL, &type, SETTING_COL, &setting, -1);
+ if (type == SOUND_TYPE_VISUAL_BELL)
+ return FALSE;
+
+ if (setting == SOUND_OFF || setting == SOUND_CUSTOM)
+ (*num_custom)++;
+
+ return FALSE;
+}
+
+static void
+dump_theme (GladeXML *dialog)
+{
+ int num_custom;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ char *parent;
+
+ num_custom = 0;
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (WID ("sounds_treeview")));
+ gtk_tree_model_foreach (model, (GtkTreeModelForeachFunc) count_customised_sounds, &num_custom);
+
+ g_debug ("%d customised sounds", num_custom);
+
+ model = gtk_combo_box_get_model (GTK_COMBO_BOX (WID ("sound_theme_combobox")));
+ /* Get the current theme's name, and set the parent */
+ if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (WID ("sound_theme_combobox")), &iter) == FALSE)
+ return;
+
+ if (num_custom == 0) {
+ gtk_tree_model_get (model, &iter, THEME_PARENT_ID_COL, &parent, -1);
+ if (parent != NULL) {
+ set_combox_for_theme_name (dialog, parent);
+ g_free (parent);
+ }
+ gtk_tree_model_get_iter_first (model, &iter);
+ while (1) {
+ gtk_tree_model_get (model, &iter, THEME_PARENT_ID_COL, &parent, -1);
+ if (parent != NULL && strcmp (parent, CUSTOM_THEME_NAME) != 0) {
+ gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
+ break;
+ }
+ if (gtk_tree_model_iter_next (model, &iter) == FALSE)
+ break;
+ }
+
+ delete_custom_theme_dir ();
+ } else {
+ gtk_tree_model_get (model, &iter, THEME_IDENTIFIER_COL, &parent, -1);
+ if (strcmp (parent, CUSTOM_THEME_NAME) != 0) {
+ gtk_list_store_insert_with_values (GTK_LIST_STORE (model), NULL, G_MAXINT,
+ THEME_DISPLAY_COL, _("Custom"),
+ THEME_IDENTIFIER_COL, CUSTOM_THEME_NAME,
+ THEME_PARENT_ID_COL, parent,
+ -1);
+ } else {
+ g_free (parent);
+ gtk_tree_model_get (model, &iter, THEME_PARENT_ID_COL, &parent, -1);
+ }
+
+ g_debug ("The parent theme is: %s", parent);
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (WID ("sounds_treeview")));
+ save_custom_theme (model, parent);
+ g_free (parent);
+
+ set_combox_for_theme_name (dialog, CUSTOM_THEME_NAME);
+ }
+}
+
+static void
+setting_column_edited (GtkCellRendererText *renderer,
+ gchar *path,
+ gchar *new_text,
+ GladeXML *dialog)
+{
+ GtkTreeModel *model, *tree_model;
+ GtkTreeIter iter, tree_iter;
+ SoundType type;
+ char *text;
+ int setting;
+
+ if (new_text == NULL)
+ return;
+
+ g_object_get (G_OBJECT (renderer),
+ "model", &model,
+ NULL);
+
+ tree_model = gtk_tree_view_get_model (GTK_TREE_VIEW (WID ("sounds_treeview")));
+ if (gtk_tree_model_get_iter_from_string (tree_model, &tree_iter, path) == FALSE)
+ return;
+
+ gtk_tree_model_get (tree_model, &tree_iter, TYPE_COL, &type, -1);
+
+ gtk_tree_model_get_iter_first (model, &iter);
+ while (1) {
+ gtk_tree_model_get (model, &iter, 0, &text, 1, &setting, -1);
+ if (g_utf8_collate (text, new_text) == 0) {
+ if (type == SOUND_TYPE_NORMAL || type == SOUND_TYPE_FEEDBACK || type == SOUND_TYPE_AUDIO_BELL) {
+ char *filename;
+
+ if (setting == SOUND_CUSTOM) {
+ filename = get_sound_filename (dialog);
+ if (filename == NULL)
+ break;
+ } else {
+ filename = NULL;
+ }
+
+ gtk_tree_store_set (GTK_TREE_STORE (tree_model),
+ &tree_iter,
+ SETTING_COL, setting,
+ HAS_PREVIEW_COL, setting != SOUND_OFF,
+ FILENAME_COL, filename,
+ -1);
+
+ g_debug ("Something changed, dump theme");
+ dump_theme (dialog);
+
+ break;
+ } else if (type == SOUND_TYPE_VISUAL_BELL) {
+ GConfClient *client;
+
+ client = gconf_client_get_default ();
+ visual_bell_setting_to_gconf (client, setting);
+ g_object_unref (client);
+ gtk_tree_store_set (GTK_TREE_STORE (tree_model),
+ &tree_iter,
+ SETTING_COL, setting,
+ -1);
+ break;
+ }
+ g_assert_not_reached ();
+ }
+
+ if (gtk_tree_model_iter_next (model, &iter) == FALSE)
+ break;
+ }
+}
+
+/* Functions to toggle whether the Input feedback sounds are editable */
+static gboolean
+input_feedback_foreach (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ int type;
+ gboolean enabled = GPOINTER_TO_INT (data);
+
+ gtk_tree_model_get (model, iter, TYPE_COL, &type, -1);
+ if (type == SOUND_TYPE_FEEDBACK) {
+ gtk_tree_store_set (GTK_TREE_STORE (model), iter,
+ SENSITIVE_COL, enabled,
+ HAS_PREVIEW_COL, enabled,
+ -1);
+ }
+ return FALSE;
+}
+
+static void
+set_input_feedback_enabled (GladeXML *dialog, gboolean enabled)
+{
+ GtkTreeModel *model;
+
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (WID ("sounds_treeview")));
+ gtk_tree_model_foreach (model, input_feedback_foreach, GINT_TO_POINTER (enabled));
+}
+
+static void
+input_feedback_changed_cb (GConfClient *client,
+ guint cnxn_id,
+ GConfEntry *entry,
+ GladeXML *dialog)
+{
+ gboolean input_feedback_enabled;
+
+ input_feedback_enabled = gconf_client_get_bool (client, INPUT_SOUNDS_KEY, NULL);
+ set_input_feedback_enabled (dialog, input_feedback_enabled);
+}
+
+/* Functions to toggle whether the audible bell sound is editable */
+static gboolean
+audible_bell_foreach (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ int type;
+ gboolean enabled = GPOINTER_TO_INT (data);
+
+ gtk_tree_model_get (model, iter, TYPE_COL, &type, -1);
+ if (type == SOUND_TYPE_AUDIO_BELL) {
+ gtk_tree_store_set (GTK_TREE_STORE (model), iter,
+ SENSITIVE_COL, enabled,
+ HAS_PREVIEW_COL, enabled,
+ -1);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static void
+set_audible_bell_enabled (GladeXML *dialog, gboolean enabled)
+{
+ GtkTreeModel *model;
+
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (WID ("sounds_treeview")));
+ gtk_tree_model_foreach (model, audible_bell_foreach, GINT_TO_POINTER (enabled));
+}
+
+static void
+audible_bell_changed_cb (GConfClient *client,
+ guint cnxn_id,
+ GConfEntry *entry,
+ GladeXML *dialog)
+{
+ gboolean audio_bell_enabled;
+
+ audio_bell_enabled = gconf_client_get_bool (client, AUDIO_BELL_KEY, NULL);
+ set_audible_bell_enabled (dialog, audio_bell_enabled);
+}
+
+static gboolean
+theme_changed_custom_reinit (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ int type;
+
+ gtk_tree_model_get (model, iter, TYPE_COL, &type, -1);
+ if (type != -1 && type != SOUND_TYPE_VISUAL_BELL) {
+ gtk_tree_store_set (GTK_TREE_STORE (model), iter,
+ SETTING_COL, SOUND_BUILTIN,
+ -1);
+ }
+ return FALSE;
+}
+
+static int
+get_file_type (const char *sound_name, char **linked_name)
+{
+ char *name, *filename;
+
+ *linked_name = NULL;
+
+ name = g_strdup_printf ("%s.disabled", sound_name);
+ filename = custom_theme_dir_path (name);
+ g_free (name);
+
+ if (g_file_test (filename, G_FILE_TEST_IS_REGULAR) != FALSE) {
+ g_free (filename);
+ return SOUND_OFF;
+ }
+ g_free (filename);
+
+ /* We only check for .ogg files because those are the
+ * only ones we create */
+ name = g_strdup_printf ("%s.ogg", sound_name);
+ filename = custom_theme_dir_path (name);
+ g_free (name);
+
+ if (g_file_test (filename, G_FILE_TEST_IS_SYMLINK) != FALSE) {
+ *linked_name = g_file_read_link (filename, NULL);
+ g_free (filename);
+ return SOUND_CUSTOM;
+ }
+ g_free (filename);
+
+ return SOUND_BUILTIN;
+}
+
+static gboolean
+theme_changed_custom_init (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ char **sound_names;
+
+ gtk_tree_model_get (model, iter, SOUND_NAMES_COL, &sound_names, -1);
+ if (sound_names != NULL) {
+ char *filename;
+ int type;
+
+ type = get_file_type (sound_names[0], &filename);
+
+ gtk_tree_store_set (GTK_TREE_STORE (model), iter,
+ SETTING_COL, type,
+ HAS_PREVIEW_COL, type != SOUND_OFF,
+ FILENAME_COL, filename,
+ -1);
+ g_strfreev (sound_names);
+ g_free (filename);
+ }
+ return FALSE;
+}
+
+static gboolean
+custom_treeview_button_press_event_cb (GtkWidget *tree_view,
+ GdkEventButton *event,
+ GladeXML *dialog)
+{
+ GtkTreePath *path;
+ GtkTreeViewColumn *column;
+ GdkEventButton *button_event = (GdkEventButton *) event;
+
+ if (event->type != GDK_BUTTON_PRESS)
+ return TRUE;
+
+ if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (tree_view),
+ button_event->x, button_event->y,
+ &path, &column, NULL, NULL)) {
+ GObject *preview_column;
+
+ preview_column = g_object_get_data (G_OBJECT (tree_view), "preview-column");
+ if (column == (GtkTreeViewColumn *) preview_column) {
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ char **sound_names;
+ ca_context *ctx;
+
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_view));
+ if (gtk_tree_model_get_iter (model, &iter, path) == FALSE) {
+ gtk_tree_path_free (path);
+ return FALSE;
+ }
+ gtk_tree_path_free (path);
+
+ gtk_tree_model_get (model, &iter, SOUND_NAMES_COL, &sound_names, -1);
+ if (sound_names == NULL)
+ return FALSE;
+
+ ctx = ca_gtk_context_get ();
+ ca_gtk_play_for_widget (GTK_WIDGET (tree_view), 0,
+ CA_PROP_APPLICATION_NAME, _("Sound Preferences"),
+ CA_PROP_EVENT_ID, sound_names[0],
+ CA_PROP_EVENT_DESCRIPTION, _("Testing event sound"),
+ NULL);
+
+ g_strfreev (sound_names);
+
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+void
+setup_sound_theme_custom (GladeXML *dialog, gboolean have_xkb)
+{
+ GtkTreeStore *store;
+ GtkTreeModel *custom_model;
+ GtkTreeViewColumn *column;
+ GtkCellRenderer *renderer;
+ GtkTreeIter iter, parent;
+ GConfClient *client;
+ CategoryType type;
+ gboolean input_feedback_enabled, audible_bell_enabled;
+ int visual_bell_setting;
+ char *theme_name;
+ guint i;
+
+ client = gconf_client_get_default ();
+ visual_bell_setting = visual_bell_gconf_to_setting (client);
+
+ /* Set up the model for the custom view */
+ store = gtk_tree_store_new (NUM_COLS, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_STRV);
+
+ /* The first column with the categories/sound names */
+ renderer = gtk_cell_renderer_text_new ();
+ column = gtk_tree_view_column_new_with_attributes ("Display", renderer,
+ "text", DISPLAY_COL,
+ "sensitive", SENSITIVE_COL,
+ NULL);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (WID ("sounds_treeview")), column);
+
+ /* The 2nd column with the sound settings */
+ renderer = gtk_cell_renderer_combo_new();
+ g_signal_connect (renderer, "edited", G_CALLBACK (setting_column_edited), dialog);
+ g_signal_connect (renderer, "editing-started", G_CALLBACK (combobox_editing_started), dialog);
+ custom_model = GTK_TREE_MODEL (gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_INT));
+ fill_custom_model (GTK_LIST_STORE (custom_model), NULL);
+ g_object_set (renderer, "model", custom_model, "has-entry", FALSE, "editable", TRUE, "text-column", 0, NULL);
+ column = gtk_tree_view_column_new_with_attributes ("Setting", renderer,
+ "editable", SENSITIVE_COL,
+ "sensitive", SENSITIVE_COL,
+ "visible", TRUE,
+ NULL);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (WID ("sounds_treeview")), column);
+ gtk_tree_view_column_set_cell_data_func (column, renderer, setting_set_func, NULL, NULL);
+
+ /* The 3rd column with the preview pixbuf */
+ renderer = gtk_cell_renderer_pixbuf_new ();
+ g_object_set (renderer,
+ "mode", GTK_CELL_RENDERER_MODE_ACTIVATABLE,
+ "icon-name", "media-playback-start",
+ "stock-size", GTK_ICON_SIZE_MENU,
+ "xpad", PREVIEW_BUTTON_XPAD,
+ NULL);
+ column = gtk_tree_view_column_new_with_attributes ("Preview", renderer,
+ "visible", HAS_PREVIEW_COL,
+ NULL);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (WID ("sounds_treeview")), column);
+ g_object_set_data (G_OBJECT (WID ("sounds_treeview")), "preview-column", column);
+
+ gtk_tree_view_set_model (GTK_TREE_VIEW (WID ("sounds_treeview")), GTK_TREE_MODEL (store));
+ gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (WID ("sounds_treeview")), FALSE);
+
+ g_signal_connect (WID ("sounds_treeview"), "button-press-event",
+ G_CALLBACK (custom_treeview_button_press_event_cb), dialog);
+
+ /* Fill in the model */
+ type = CATEGORY_INVALID;
+
+ for (i = 0; ; i++) {
+ GtkTreeIter *_parent;
+
+ if (sounds[i].category == -1)
+ break;
+
+ if (sounds[i].type == SOUND_TYPE_VISUAL_BELL && have_xkb == FALSE)
+ continue;
+
+ /* Is it a new type of sound? */
+ if (sounds[i].category == type && type != CATEGORY_INVALID && type != CATEGORY_BELL)
+ _parent = &parent;
+ else
+ _parent = NULL;
+
+ if (sounds[i].type == SOUND_TYPE_VISUAL_BELL)
+ gtk_tree_store_insert_with_values (store, &iter, _parent, G_MAXINT,
+ DISPLAY_COL, _(sounds[i].display_name),
+ SETTING_COL, visual_bell_setting,
+ TYPE_COL, sounds[i].type,
+ HAS_PREVIEW_COL, FALSE,
+ SENSITIVE_COL, TRUE,
+ -1);
+ else if (sounds[i].type != -1)
+ gtk_tree_store_insert_with_values (store, &iter, _parent, G_MAXINT,
+ DISPLAY_COL, _(sounds[i].display_name),
+ SETTING_COL, SOUND_BUILTIN,
+ TYPE_COL, sounds[i].type,
+ SOUND_NAMES_COL, sounds[i].names,
+ HAS_PREVIEW_COL, TRUE,
+ SENSITIVE_COL, TRUE,
+ -1);
+ else
+ /* Category */
+ gtk_tree_store_insert_with_values (store, &iter, _parent, G_MAXINT,
+ DISPLAY_COL, _(sounds[i].display_name),
+ SETTING_COL, SOUND_UNSET,
+ TYPE_COL, sounds[i].type,
+ SENSITIVE_COL, TRUE,
+ HAS_PREVIEW_COL, FALSE,
+ -1);
+
+ /* If we didn't set a parent already, set one in case we need it later */
+ if (_parent == NULL)
+ parent = iter;
+ type = sounds[i].category;
+ }
+
+ gtk_tree_view_expand_all (GTK_TREE_VIEW (WID ("sounds_treeview")));
+
+ /* Listen to GConf for a bunch of keys */
+ input_feedback_enabled = gconf_client_get_bool (client, INPUT_SOUNDS_KEY, NULL);
+ if (input_feedback_enabled == FALSE)
+ set_input_feedback_enabled (dialog, FALSE);
+ gconf_client_notify_add (client, INPUT_SOUNDS_KEY,
+ (GConfClientNotifyFunc) input_feedback_changed_cb, dialog, NULL, NULL);
+
+ audible_bell_enabled = gconf_client_get_bool (client, AUDIO_BELL_KEY, NULL);
+ if (audible_bell_enabled == FALSE)
+ set_audible_bell_enabled (dialog, FALSE);
+ gconf_client_notify_add (client, AUDIO_BELL_KEY,
+ (GConfClientNotifyFunc) audible_bell_changed_cb, dialog, NULL, NULL);
+
+ /* Setup the default values if we're using the custom theme */
+ theme_name = gconf_client_get_string (client, SOUND_THEME_KEY, NULL);
+ if (theme_name != NULL && strcmp (theme_name, CUSTOM_THEME_NAME) == 0)
+ gtk_tree_model_foreach (GTK_TREE_MODEL (store), theme_changed_custom_init, NULL);
+ g_free (theme_name);
+
+ g_object_unref (G_OBJECT (client));
+}
+
Added: trunk/capplets/sound/sound-theme.h
==============================================================================
--- (empty file)
+++ trunk/capplets/sound/sound-theme.h Sun Jul 27 23:32:35 2008
@@ -0,0 +1,31 @@
+/* -*- mode: c; style: linux -*- */
+/* -*- c-basic-offset: 2 -*- */
+
+/* sound-theme.h
+ * Copyright (C) 2008 Bastien Nocera <hadess hadess net>
+ *
+ * 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, 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.
+ */
+#ifndef __SOUND_THEME_HH__
+#define __SOUND_THEME_HH__
+
+#include <gtk/gtk.h>
+#include <glade/glade.h>
+
+void setup_sound_theme (GladeXML *dialog);
+void setup_sound_theme_custom (GladeXML *dialog, gboolean have_xkb);
+
+#endif /* __SOUND_THEME_HH__ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]