From dc01a56fd15939230c23269518313ac9864958d7 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 30 May 2008 17:05:51 +0000 Subject: add gtk module git-svn-id: file:///home/lennart/svn/public/libcanberra/trunk@39 01b60673-d06a-42c0-afdd-89cb8e0f78ac --- src/Makefile.am | 19 +++- src/canberra-gtk-module.c | 277 ++++++++++++++++++++++++++++++++++++++++++++++ src/canberra-gtk.c | 18 ++- src/canberra-gtk.h | 8 +- 4 files changed, 313 insertions(+), 9 deletions(-) create mode 100644 src/canberra-gtk-module.c (limited to 'src') 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 # . +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 + . +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#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(¶m_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(¶m_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 -- cgit