summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2008-05-30 17:05:51 +0000
committerLennart Poettering <lennart@poettering.net>2008-05-30 17:05:51 +0000
commitdc01a56fd15939230c23269518313ac9864958d7 (patch)
tree1e2fe661a7814f1d35f4ed1449814ac0cbb40bec
parent0311453fc6f4bc819a6ba4563b77cedef569d8ab (diff)
add gtk module
git-svn-id: file:///home/lennart/svn/public/libcanberra/trunk@39 01b60673-d06a-42c0-afdd-89cb8e0f78ac
-rw-r--r--configure.ac9
-rw-r--r--src/Makefile.am19
-rw-r--r--src/canberra-gtk-module.c277
-rw-r--r--src/canberra-gtk.c18
-rw-r--r--src/canberra-gtk.h8
5 files changed, 320 insertions, 11 deletions
diff --git a/configure.ac b/configure.ac
index bac0244..e8f5a38 100644
--- a/configure.ac
+++ b/configure.ac
@@ -274,6 +274,10 @@ AM_CONDITIONAL([HAVE_PULSE], [test "x$HAVE_PULSE" = x1])
PKG_CHECK_MODULES(VORBIS, [ vorbisfile ])
PKG_CHECK_MODULES(GTK, [ gtk+-2.0 ])
+GTK_VERSION=`$PKG_CONFIG --variable=gtk_binary_version gtk+-2.0`
+GTK_MODULES_DIR="${libdir}/gtk-2.0/modules"
+AC_SUBST(GTK_MODULES_DIR)
+
###################################
# Output #
###################################
@@ -306,6 +310,7 @@ echo "
CFLAGS: ${CFLAGS}
C++-Compiler: ${CXX}
CXXFLAGS: ${CXXFLAGS}
- Enable Alsa: ${ENABLE_ALSA}
- Enable Pulse: ${ENABLE_PULSE}
+ Enable ALSA: ${ENABLE_ALSA}
+ Enable PulseAudio: ${ENABLE_PULSE}
+ GTK Modules Directory: ${GTK_MODULES_DIR}
"
diff --git a/src/Makefile.am b/src/Makefile.am
index 6dc6e89..f8c1366 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -18,6 +18,8 @@
# License along with libcanberra. If not, If not, see
# <http://www.gnu.org/licenses/>.
+moduledir = @GTK_MODULES_DIR@
+
AM_CFLAGS = $(PTHREAD_CFLAGS)
AM_CXXFLAGS = $(PTHREAD_CFLAGS)
AM_LDADD = $(PTHREAD_LIBS)
@@ -26,6 +28,9 @@ lib_LTLIBRARIES = \
libcanberra.la \
libcanberra-gtk.la
+module_LTLIBRARIES = \
+ libcanberra-gtk-module.la
+
noinst_PROGRAMS = \
test-canberra
@@ -55,10 +60,22 @@ libcanberra_gtk_la_SOURCES = \
canberra-gtk.h \
canberra-gtk.c
libcanberra_gtk_la_LIBADD = \
- $(GTK_LIBS)
+ $(GTK_LIBS) \
+ libcanberra.la
libcanberra_gtk_la_CFLAGS = \
$(GTK_CFLAGS)
+libcanberra_gtk_module_la_SOURCES = \
+ canberra-gtk-module.c
+libcanberra_gtk_module_la_LIBADD = \
+ $(GTK_LIBS) \
+ libcanberra.la \
+ libcanberra-gtk.la
+libcanberra_gtk_module_la_LDFLAGS = \
+ -avoid-version -module -export-dynamic
+libcanberra_gtk_module_la_CFLAGS = \
+ $(GTK_CFLAGS)
+
test_canberra_SOURCES = \
test-canberra.c
test_canberra_LDADD = \
diff --git a/src/canberra-gtk-module.c b/src/canberra-gtk-module.c
new file mode 100644
index 0000000..2dda4b7
--- /dev/null
+++ b/src/canberra-gtk-module.c
@@ -0,0 +1,277 @@
+/* $Id$ */
+
+/***
+ This file is part of libcanberra.
+
+ Copyright 2008 Lennart Poettering
+
+ libcanberra is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation, either version 2.1 of the
+ License, or (at your option) any later version.
+
+ libcanberra 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 Lesser General Public
+ License along with libcanberra. If not, If not, see
+ <http://www.gnu.org/licenses/>.
+***/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <gtk/gtk.h>
+
+#include "canberra-gtk.h"
+
+static guint
+ signal_id_message_dialog_show,
+ signal_id_dialog_response,
+ signal_id_menu_show,
+ signal_id_menu_hide,
+ signal_id_check_menu_item_toggled,
+ signal_id_menu_item_activate,
+ signal_id_toggle_button_toggled,
+ signal_id_button_clicked;
+
+static const char *translate_message_tye(GtkMessageType mt) {
+ static const char *const message_type_table[] = {
+ [GTK_MESSAGE_INFO] = "dialog-information",
+ [GTK_MESSAGE_WARNING] = "dialog-warning",
+ [GTK_MESSAGE_QUESTION] = "dialog-question",
+ [GTK_MESSAGE_ERROR] = "dialog-error",
+ [GTK_MESSAGE_OTHER] = NULL
+ };
+
+ if (mt >= G_N_ELEMENTS(message_type_table))
+ return NULL;
+
+ return message_type_table[mt];
+}
+
+static const char *translate_response(int response) {
+ static const char *const response_table[] = {
+ [-GTK_RESPONSE_NONE] = NULL,
+ [-GTK_RESPONSE_REJECT] = "dialog-cancel",
+ [-GTK_RESPONSE_DELETE_EVENT] = "dialog-cancel",
+ [-GTK_RESPONSE_ACCEPT] = "dialog-ok",
+ [-GTK_RESPONSE_OK] = "dialog-ok",
+ [-GTK_RESPONSE_CANCEL] = "dialog-cancel",
+ [-GTK_RESPONSE_CLOSE] = "dialog-ok",
+ [-GTK_RESPONSE_YES] = "dialog-ok",
+ [-GTK_RESPONSE_NO] = "dialog-cancel",
+ [-GTK_RESPONSE_APPLY] = "dialog-ok",
+ [-GTK_RESPONSE_HELP] = NULL,
+ };
+
+ if (response >= 0)
+ return NULL;
+
+ if ((unsigned) -response >= G_N_ELEMENTS(response_table))
+ return NULL;
+
+ return response_table[-response];
+}
+
+static gboolean is_child_of_combo_box(GtkWidget *w) {
+
+ while (w) {
+
+ if (GTK_IS_COMBO_BOX(w))
+ return TRUE;
+
+ w = gtk_widget_get_parent(w);
+ }
+
+ return FALSE;
+}
+
+static GtkDialog* find_parent_dialog(GtkWidget *w) {
+
+ while (w) {
+
+ if (GTK_IS_DIALOG(w))
+ return GTK_DIALOG(w);
+
+ w = gtk_widget_get_parent(w);
+ }
+
+ return NULL;
+}
+
+static gboolean emission_hook_cb(GSignalInvocationHint *hint, guint n_param_values, const GValue *param_values, gpointer data) {
+ int ret = CA_SUCCESS;
+ static GQuark disable_sound_quark = 0;
+ GObject *object;
+
+ /* This is the same quark used by libgnomeui! */
+ if (!disable_sound_quark)
+ disable_sound_quark = g_quark_from_static_string("gnome_disable_sound_events");
+
+ object = g_value_get_object(&param_values[0]);
+
+ if (g_object_get_qdata(object, disable_sound_quark))
+ return TRUE;
+
+ if (!GTK_IS_WIDGET(object))
+ return TRUE;
+
+ if (!GTK_WIDGET_DRAWABLE(object))
+ return TRUE;
+
+/* g_message("signal %s on %s", g_signal_name(hint->signal_id), g_type_name(G_OBJECT_TYPE(object))); */
+
+ if (GTK_IS_MESSAGE_DIALOG(object) && hint->signal_id == signal_id_message_dialog_show) {
+ GtkMessageType mt;
+ const char *id;
+
+ g_object_get(object, "message_type", &mt, NULL);
+
+ if ((id = translate_message_tye(mt)))
+ ret = ca_gtk_play_for_widget(GTK_WIDGET(object), 0,
+ CA_PROP_EVENT_ID, id,
+ CA_PROP_EVENT_DESCRIPTION, "Message dialog shown",
+ CA_PROP_CANBERRA_CACHE_CONTROL, "permanent",
+ NULL);
+
+ /* Hmm, why do we get two of these? */
+ }
+
+ if (GTK_IS_DIALOG(object) && hint->signal_id == signal_id_dialog_response) {
+
+ int response;
+ const char *id;
+
+ response = g_value_get_int(&param_values[1]);
+
+ if ((id = translate_response(response))) {
+
+ ret = ca_gtk_play_for_widget(GTK_WIDGET(object), 0,
+ CA_PROP_EVENT_ID, id,
+ CA_PROP_EVENT_DESCRIPTION, "Dialog closed",
+ CA_PROP_CANBERRA_CACHE_CONTROL, "permanent",
+ NULL);
+ }
+ }
+
+ if (GTK_IS_MENU(object)) {
+
+ /* This doesn't work */
+
+ if (hint->signal_id == signal_id_menu_show)
+ ret = ca_gtk_play_for_widget(GTK_WIDGET(object), 0,
+ CA_PROP_EVENT_ID, "menu-popup",
+ CA_PROP_EVENT_DESCRIPTION, "Menu popped up",
+ CA_PROP_CANBERRA_CACHE_CONTROL, "permanent",
+ NULL);
+ else if (hint->signal_id == signal_id_menu_hide)
+ ret = ca_gtk_play_for_widget(GTK_WIDGET(object), 0,
+ CA_PROP_EVENT_ID, "menu-popdown",
+ CA_PROP_EVENT_DESCRIPTION, "Menu popped up",
+ CA_PROP_CANBERRA_CACHE_CONTROL, "permanent",
+ NULL);
+ }
+
+ if (GTK_IS_CHECK_MENU_ITEM(object) && hint->signal_id == signal_id_check_menu_item_toggled) {
+
+ if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(object)))
+ ret = ca_gtk_play_for_widget(GTK_WIDGET(object), 0,
+ CA_PROP_EVENT_ID, "button-toggle-on",
+ CA_PROP_EVENT_DESCRIPTION, "Check menu item checked",
+ CA_PROP_CANBERRA_CACHE_CONTROL, "permanent",
+ NULL);
+ else
+ ret = ca_gtk_play_for_widget(GTK_WIDGET(object), 0,
+ CA_PROP_EVENT_ID, "button-toggle-off",
+ CA_PROP_EVENT_DESCRIPTION, "Check menu item unchecked",
+ CA_PROP_CANBERRA_CACHE_CONTROL, "permanent",
+ NULL);
+
+ } else if (GTK_IS_MENU_ITEM(object) && hint->signal_id == signal_id_menu_item_activate) {
+
+ if (!GTK_MENU_ITEM(object)->submenu)
+ ret = ca_gtk_play_for_widget(GTK_WIDGET(object), 0,
+ CA_PROP_EVENT_ID, "menu-click",
+ CA_PROP_EVENT_DESCRIPTION, "Menu item clicked",
+ CA_PROP_CANBERRA_CACHE_CONTROL, "permanent",
+ NULL);
+ }
+
+ if (GTK_IS_TOGGLE_BUTTON(object) && hint->signal_id == signal_id_toggle_button_toggled) {
+
+
+ if (!is_child_of_combo_box(GTK_WIDGET(object))) {
+
+ /* We don't want to play this sound if this is a toggle
+ * button belonging to combo box. */
+
+ if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(object)))
+ ret = ca_gtk_play_for_widget(GTK_WIDGET(object), 0,
+ CA_PROP_EVENT_ID, "button-toggle-on",
+ CA_PROP_EVENT_DESCRIPTION, "Toggle button checked",
+ CA_PROP_CANBERRA_CACHE_CONTROL, "permanent",
+ NULL);
+ else
+ ret = ca_gtk_play_for_widget(GTK_WIDGET(object), 0,
+ CA_PROP_EVENT_ID, "button-toggle-off",
+ CA_PROP_EVENT_DESCRIPTION, "Toggle button unchecked",
+ CA_PROP_CANBERRA_CACHE_CONTROL, "permanent",
+ NULL);
+ }
+
+ } else if (GTK_IS_BUTTON(object) && !GTK_IS_TOGGLE_BUTTON(object) && hint->signal_id == signal_id_button_clicked) {
+ GtkDialog *dialog;
+ gboolean dont_play = FALSE;
+
+ if ((dialog = find_parent_dialog(GTK_WIDGET(object)))) {
+ int response;
+
+ /* Don't play the click sound if this is a response widget
+ * we will generate a dialog-xxx event sound anyway. */
+
+ response = gtk_dialog_get_response_for_widget(dialog, GTK_WIDGET(object));
+ dont_play = !!translate_response(response);
+ }
+
+ if (!dont_play)
+ ret = ca_gtk_play_for_widget(GTK_WIDGET(object), 0,
+ CA_PROP_EVENT_ID, "button-click",
+ CA_PROP_EVENT_DESCRIPTION, "Button clicked",
+ CA_PROP_CANBERRA_CACHE_CONTROL, "permanent",
+ NULL);
+ }
+
+ if (ret != CA_SUCCESS)
+ g_warning("Failed to play event sound: %s", ca_strerror(ret));
+
+ return TRUE;
+}
+
+
+static void install_hook(GType type, const char *signal, guint *sn) {
+
+ /* I've no idea what this is for. libgnomeui does it, and thus we
+ * do it too. Someone with more gobject-fu should say something
+ * about this */
+ g_type_class_unref(g_type_class_ref(type));
+
+ *sn = g_signal_lookup(signal, type);
+ g_signal_add_emission_hook(*sn, 0, emission_hook_cb, NULL, NULL);
+}
+
+void gtk_module_init(gint *argc, gchar ***argv[]);
+
+void gtk_module_init(gint *argc, gchar ***argv[]) {
+ install_hook(GTK_TYPE_MESSAGE_DIALOG, "show", &signal_id_message_dialog_show);
+ install_hook(GTK_TYPE_DIALOG, "response", &signal_id_dialog_response);
+ install_hook(GTK_TYPE_MENU, "show", &signal_id_menu_show);
+ install_hook(GTK_TYPE_MENU, "hide", &signal_id_menu_hide);
+ install_hook(GTK_TYPE_MENU_ITEM, "activate", &signal_id_menu_item_activate);
+ install_hook(GTK_TYPE_CHECK_MENU_ITEM, "toggled", &signal_id_check_menu_item_toggled);
+ install_hook(GTK_TYPE_TOGGLE_BUTTON, "toggled", &signal_id_toggle_button_toggled);
+ install_hook(GTK_TYPE_BUTTON, "clicked", &signal_id_button_clicked);
+}
diff --git a/src/canberra-gtk.c b/src/canberra-gtk.c
index 81052d4..2d3edb4 100644
--- a/src/canberra-gtk.c
+++ b/src/canberra-gtk.c
@@ -61,7 +61,7 @@ static GtkWindow* get_toplevel(GtkWidget *w) {
return GTK_WINDOW(w);
}
-int ca_gtk_proplist_set_for_window(ca_proplist *p, GtkWidget *widget) {
+int ca_gtk_proplist_set_for_widget(ca_proplist *p, GtkWidget *widget) {
GtkWindow *w;
int ret;
const char *t, *role;
@@ -131,7 +131,7 @@ int ca_gtk_proplist_set_for_event(ca_proplist *p, GdkEvent *e) {
gdk_window_get_user_data(gw, (gpointer*) &w);
if (w)
- if ((ret = ca_gtk_proplist_set_for_window(p, w)) < 0)
+ if ((ret = ca_gtk_proplist_set_for_widget(p, w)) < 0)
return ret;
}
@@ -169,7 +169,7 @@ int ca_gtk_proplist_set_for_event(ca_proplist *p, GdkEvent *e) {
return CA_SUCCESS;
}
-int ca_gtk_play_for_window(GtkWidget *w, uint32_t id, ...) {
+int ca_gtk_play_for_widget(GtkWidget *w, uint32_t id, ...) {
va_list ap;
int ret;
ca_proplist *p;
@@ -179,7 +179,7 @@ int ca_gtk_play_for_window(GtkWidget *w, uint32_t id, ...) {
if ((ret = ca_proplist_create(&p)) < 0)
return ret;
- if ((ret = ca_gtk_proplist_set_for_window(p, w)) < 0)
+ if ((ret = ca_gtk_proplist_set_for_widget(p, w)) < 0)
goto fail;
va_start(ap, id);
@@ -226,3 +226,13 @@ fail:
return ret;
}
+
+void ca_gtk_widget_disable_sounds(GtkWidget *w, gboolean enable) {
+ static GQuark disable_sound_quark = 0;
+
+ /* This is the same quark used by libgnomeui! */
+ if (!disable_sound_quark)
+ disable_sound_quark = g_quark_from_static_string("gnome_disable_sound_events");
+
+ g_object_set_qdata(G_OBJECT(w), disable_sound_quark, GINT_TO_POINTER(!!enable));
+}
diff --git a/src/canberra-gtk.h b/src/canberra-gtk.h
index e3b49d3..3c6fa2c 100644
--- a/src/canberra-gtk.h
+++ b/src/canberra-gtk.h
@@ -28,12 +28,12 @@
ca_context *ca_gtk_context_get(void);
-int ca_gtk_play_for_window(GtkWidget *w, uint32_t id, ...) CA_GCC_SENTINEL;
+int ca_gtk_proplist_set_for_widget(ca_proplist *p, GtkWidget *w);
+int ca_gtk_play_for_widget(GtkWidget *w, uint32_t id, ...) CA_GCC_SENTINEL;
+int ca_gtk_proplist_set_for_event(ca_proplist *p, GdkEvent *e);
int ca_gtk_play_for_event(GdkEvent *e, uint32_t id, ...) CA_GCC_SENTINEL;
-int ca_gtk_proplist_set_for_window(ca_proplist *p, GtkWidget *w);
-
-int ca_gtk_proplist_set_for_event(ca_proplist *p, GdkEvent *e);
+void ca_gtk_widget_disable_sounds(GtkWidget *w, gboolean enable);
#endif