summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2008-06-10 13:00:58 +0000
committerLennart Poettering <lennart@poettering.net>2008-06-10 13:00:58 +0000
commitf7081c9e82c7dea2887bb5e23f8c20c01aa703b0 (patch)
tree1b32762c13c06ea9cc0ab61a26001b3f9be2f8c6
parentb1dccb6dfdab87e5e7d84e7e687eef93319aa332 (diff)
extend the the gtk module
git-svn-id: file:///home/lennart/svn/public/libcanberra/trunk@60 01b60673-d06a-42c0-afdd-89cb8e0f78ac
-rw-r--r--src/Makefile.am36
-rw-r--r--src/canberra-gtk-module.c261
-rw-r--r--src/driver.h1
-rw-r--r--src/dso.c54
4 files changed, 288 insertions, 64 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 3acf30e..01e8b80 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -51,6 +51,8 @@ libcanberra_la_CFLAGS = \
$(VORBIS_CFLAGS)
libcanberra_la_LIBADD = \
$(VORBIS_LIBS)
+libcanberra_la_LDFLAGS = \
+ -export-dynamic
if HAVE_PULSE
if BUILTIN_PULSE
@@ -70,9 +72,17 @@ lib_LTLIBRARIES += \
libcanberra_pulse_la_SOURCES = \
pulse.c
libcanberra_pulse_la_CFLAGS = \
- $(PULSE_CFLAGS)
+ $(PULSE_CFLAGS) \
+ -Ddriver_open=pulse_driver_open \
+ -Ddriver_destroy=pulse_driver_destroy \
+ -Ddriver_change_device=pulse_driver_change_device \
+ -Ddriver_change_props=pulse_driver_change_props \
+ -Ddriver_play=pulse_driver_play \
+ -Ddriver_cancel=pulse_driver_cancel \
+ -Ddriver_cache=pulse_driver_cache
libcanberra_pulse_la_LIBADD = \
- $(PULSE_LIBS)
+ $(PULSE_LIBS) \
+ libcanberra.la
libcanberra_pulse_la_LDFLAGS = \
-avoid-version -module -export-dynamic
@@ -97,9 +107,17 @@ lib_LTLIBRARIES += \
libcanberra_alsa_la_SOURCES = \
alsa.c
libcanberra_alsa_la_CFLAGS = \
- $(ALSA_CFLAGS)
+ $(ALSA_CFLAGS) \
+ -Ddriver_open=alsa_driver_open \
+ -Ddriver_destroy=alsa_driver_destroy \
+ -Ddriver_change_device=alsa_driver_change_device \
+ -Ddriver_change_props=alsa_driver_change_props \
+ -Ddriver_play=alsa_driver_play \
+ -Ddriver_cancel=alsa_driver_cancel \
+ -Ddriver_cache=alsa_driver_cache
libcanberra_alsa_la_LIBADD = \
- $(ALSA_LIBS)
+ $(ALSA_LIBS) \
+ libcanberra.la
libcanberra_alsa_la_LDFLAGS = \
-avoid-version -module -export-dynamic
@@ -119,6 +137,16 @@ lib_LTLIBRARIES += \
libcanberra_null_la_SOURCES = \
null.c
+libcanberra_null_la_CFLAGS = \
+ -Ddriver_open=null_driver_open \
+ -Ddriver_destroy=null_driver_destroy \
+ -Ddriver_change_device=null_driver_change_device \
+ -Ddriver_change_props=null_driver_change_props \
+ -Ddriver_play=null_driver_play \
+ -Ddriver_cancel=null_driver_cancel \
+ -Ddriver_cache=null_driver_cache
+libcanberra_null_la_LIBADD = \
+ libcanberra.la
libcanberra_null_la_LDFLAGS = \
-avoid-version -module -export-dynamic
endif
diff --git a/src/canberra-gtk-module.c b/src/canberra-gtk-module.c
index c241f1f..783d04d 100644
--- a/src/canberra-gtk-module.c
+++ b/src/canberra-gtk-module.c
@@ -25,6 +25,8 @@
#endif
#include <gtk/gtk.h>
+#include <gdk/gdkx.h>
+#include <X11/Xatom.h>
#include "canberra-gtk.h"
@@ -63,11 +65,15 @@ typedef struct {
menu-popup
menu-popdown
menu-replace
+ tooltip-popup
+ tooltip-popdown
TODO:
drag-start
drag-accept
drag-fail
+ expander-toggle-on
+ expander-toggle-off
*/
@@ -86,9 +92,12 @@ static guint
signal_id_button_released,
signal_id_widget_window_state_event,
signal_id_notebook_switch_page,
- signal_id_tree_view_move_cursor;
+ signal_id_tree_view_cursor_changed,
+ signal_id_icon_view_selection_changed;
-static GQuark disable_sound_quark;
+static GQuark
+ disable_sound_quark,
+ was_hidden_quark;
/* Make sure GCC doesn't warn us about a missing prototype for this
* exported function */
@@ -172,21 +181,55 @@ static void free_sound_event(SoundEventData *d) {
g_slice_free(SoundEventData, d);
}
+static gboolean is_menu_hint(GdkWindowTypeHint hint) {
+ return
+ hint == GDK_WINDOW_TYPE_HINT_POPUP_MENU ||
+ hint == GDK_WINDOW_TYPE_HINT_DROPDOWN_MENU ||
+ hint == GDK_WINDOW_TYPE_HINT_MENU;
+}
+
static SoundEventData* filter_sound_event(SoundEventData *d) {
- GList *i;
+ GList *i, *n;
do {
- for (i = sound_event_queue.head; i; i = i->next) {
- SoundEventData *j = i->data;
+ for (i = sound_event_queue.head; i; i = n) {
+ SoundEventData *j;
+
+ j = i->data;
+ n = i->next;
if (d->object == j->object) {
+ /* Let's drop a show event immediately followed by a
+ * hide event */
+
+ if (d->signal_id == signal_id_widget_show &&
+ j->signal_id == signal_id_widget_hide) {
+
+ free_sound_event(d);
+ free_sound_event(j);
+ g_queue_delete_link(&sound_event_queue, i);
+
+ return NULL;
+ }
+
/* Let's drop widget hide events in favour of dialog
- * response */
+ * response.
+ *
+ * Let's drop widget window state events in favour of
+ * widget hide/show.
+ *
+ * Let's drop double events */
+
+ if ((d->signal_id == signal_id_widget_hide &&
+ j->signal_id == signal_id_dialog_response) ||
- if (d->signal_id == signal_id_widget_hide &&
- j->signal_id == signal_id_dialog_response) {
+ (d->signal_id == signal_id_widget_window_state_event &&
+ j->signal_id == signal_id_widget_hide) ||
+
+ (d->signal_id == signal_id_widget_window_state_event &&
+ j->signal_id == signal_id_widget_show)) {
free_sound_event(d);
d = j;
@@ -194,13 +237,45 @@ static SoundEventData* filter_sound_event(SoundEventData *d) {
break;
}
+ if ((d->signal_id == signal_id_dialog_response &&
+ j->signal_id == signal_id_widget_hide) ||
- if (d->signal_id == signal_id_dialog_response &&
- j->signal_id == signal_id_widget_hide) {
+ (d->signal_id == signal_id_widget_show &&
+ j->signal_id == signal_id_widget_window_state_event) ||
+
+ (d->signal_id == signal_id_widget_hide &&
+ j->signal_id == signal_id_widget_window_state_event) ||
+
+ (d->signal_id == j->signal_id)) {
free_sound_event(j);
g_queue_delete_link(&sound_event_queue, i);
}
+
+ } else if (GTK_IS_WINDOW(d->object) && GTK_IS_WINDOW(j->object)) {
+
+ GdkWindowTypeHint dhint, jhint;
+
+ dhint = gtk_window_get_type_hint(GTK_WINDOW(d->object));
+ jhint = gtk_window_get_type_hint(GTK_WINDOW(j->object));
+
+ if (is_menu_hint(dhint) && is_menu_hint(jhint)) {
+
+ if (d->signal_id == signal_id_widget_hide &&
+ j->signal_id == signal_id_widget_show) {
+ free_sound_event(d);
+ d = j;
+ g_queue_delete_link(&sound_event_queue, i);
+ break;
+ }
+
+ if (d->signal_id == signal_id_widget_show &&
+ j->signal_id == signal_id_widget_hide) {
+
+ free_sound_event(j);
+ g_queue_delete_link(&sound_event_queue, i);
+ }
+ }
}
}
@@ -213,38 +288,56 @@ static SoundEventData* filter_sound_event(SoundEventData *d) {
return d;
}
+static gboolean is_hidden(GdkDisplay *d, GdkWindow *w) {
+ Atom type_return;
+ gint format_return;
+ gulong nitems_return;
+ gulong bytes_after_return;
+ guchar *data = NULL;
+ gboolean r = FALSE;
+
+ if (XGetWindowProperty(GDK_DISPLAY_XDISPLAY(d), GDK_WINDOW_XID(w),
+ gdk_x11_get_xatom_by_name_for_display(d, "_NET_WM_STATE"),
+ 0, G_MAXLONG, False, XA_ATOM, &type_return,
+ &format_return, &nitems_return, &bytes_after_return,
+ &data) != Success)
+ return FALSE;
+
+ if (type_return == XA_ATOM && format_return == 32 && data) {
+ unsigned i;
+
+ for (i = 0; i < nitems_return; i++) {
+ Atom atom = ((Atom*) data)[i];
+
+ if (atom == gdk_x11_get_xatom_by_name_for_display(d, "_NET_WM_STATE_HIDDEN")) {
+ r = TRUE;
+ break;
+ }
+ }
+ }
+
+ if (type_return != None && data != NULL)
+ XFree (data);
+
+ return r;
+}
+
static void dispatch_sound_event(SoundEventData *d) {
int ret = CA_SUCCESS;
- static gboolean menu_is_popped_up = FALSE;
-
- if (!GTK_WIDGET_DRAWABLE(d->object))
- return;
+ static gboolean menu_is_popped_up = TRUE;
if (g_object_get_qdata(d->object, disable_sound_quark))
return;
if (d->signal_id == signal_id_widget_show) {
- gboolean played_sound = FALSE;
+ GdkWindowTypeHint hint;
- /* Show signals for non-windows have already been filtered out
+ /* Show/hide signals for non-windows have already been filtered out
* by the emission hook! */
- if (GTK_IS_MESSAGE_DIALOG(d->object)) {
- GtkMessageType mt;
- const char *id;
-
- g_object_get(d->object, "message_type", &mt, NULL);
-
- if ((id = translate_message_tye(mt))) {
- ret = ca_gtk_play_for_widget(GTK_WIDGET(d->object), 0,
- CA_PROP_EVENT_ID, id,
- CA_PROP_EVENT_DESCRIPTION, "Message dialog shown",
- CA_PROP_CANBERRA_CACHE_CONTROL, "permanent",
- NULL);
- played_sound = TRUE;
- }
+ hint = gtk_window_get_type_hint(GTK_WINDOW(d->object));
- } else if (GTK_IS_MENU(gtk_bin_get_child(GTK_BIN(d->object)))) {
+ if (is_menu_hint(hint)) {
if (menu_is_popped_up) {
ret = ca_gtk_play_for_widget(GTK_WIDGET(d->object), 0,
@@ -260,16 +353,46 @@ static void dispatch_sound_event(SoundEventData *d) {
NULL);
}
- played_sound = TRUE;
menu_is_popped_up = TRUE;
- }
- if (!played_sound)
+ } else if (hint == GDK_WINDOW_TYPE_HINT_TOOLTIP) {
+
ret = ca_gtk_play_for_widget(GTK_WIDGET(d->object), 0,
- CA_PROP_EVENT_ID, "window-new",
- CA_PROP_EVENT_DESCRIPTION, "Window shown",
+ CA_PROP_EVENT_ID, "tooltip-popup",
+ CA_PROP_EVENT_DESCRIPTION, "Tooltip popped up",
CA_PROP_CANBERRA_CACHE_CONTROL, "permanent",
NULL);
+
+ } else if (hint == GDK_WINDOW_TYPE_HINT_NORMAL ||
+ hint == GDK_WINDOW_TYPE_HINT_DIALOG) {
+
+ gboolean played_sound = FALSE;
+
+ if (GTK_IS_MESSAGE_DIALOG(d->object)) {
+ GtkMessageType mt;
+ const char *id;
+
+ g_object_get(d->object, "message_type", &mt, NULL);
+
+ if ((id = translate_message_tye(mt))) {
+
+ ret = ca_gtk_play_for_widget(GTK_WIDGET(d->object), 0,
+ CA_PROP_EVENT_ID, id,
+ CA_PROP_EVENT_DESCRIPTION, "Message dialog shown",
+ CA_PROP_CANBERRA_CACHE_CONTROL, "permanent",
+ NULL);
+ played_sound = TRUE;
+ }
+
+ }
+
+ if (!played_sound)
+ ret = ca_gtk_play_for_widget(GTK_WIDGET(d->object), 0,
+ CA_PROP_EVENT_ID, "window-new",
+ CA_PROP_EVENT_DESCRIPTION, "Window shown",
+ CA_PROP_CANBERRA_CACHE_CONTROL, "permanent",
+ NULL);
+ }
}
if (GTK_IS_DIALOG(d->object) && d->signal_id == signal_id_dialog_response) {
@@ -295,34 +418,53 @@ static void dispatch_sound_event(SoundEventData *d) {
}
} else if (d->signal_id == signal_id_widget_hide) {
- gboolean played_sound = FALSE;
+ GdkWindowTypeHint hint;
+
+ hint = gtk_window_get_type_hint(GTK_WINDOW(d->object));
+
+ if (is_menu_hint(hint)) {
+
+ if (GTK_IS_MENU(gtk_bin_get_child(GTK_BIN(d->object)))) {
+
+ ret = ca_gtk_play_for_widget(GTK_WIDGET(d->object), 0,
+ CA_PROP_EVENT_ID, "menu-popdown",
+ CA_PROP_EVENT_DESCRIPTION, "Menu popped down",
+ CA_PROP_CANBERRA_CACHE_CONTROL, "permanent",
+ NULL);
+ }
+
+ menu_is_popped_up = FALSE;
- if (GTK_IS_MENU(gtk_bin_get_child(GTK_BIN(d->object)))) {
+ } else if (hint == GDK_WINDOW_TYPE_HINT_TOOLTIP) {
ret = ca_gtk_play_for_widget(GTK_WIDGET(d->object), 0,
- CA_PROP_EVENT_ID, "menu-popdown",
- CA_PROP_EVENT_DESCRIPTION, "Menu popped down",
+ CA_PROP_EVENT_ID, "tooltip-popdown",
+ CA_PROP_EVENT_DESCRIPTION, "Tooltip popped down",
CA_PROP_CANBERRA_CACHE_CONTROL, "permanent",
NULL);
- played_sound = TRUE;
- menu_is_popped_up = FALSE;
- }
+ } else if (hint == GDK_WINDOW_TYPE_HINT_NORMAL ||
+ hint == GDK_WINDOW_TYPE_HINT_DIALOG) {
- if (!played_sound)
ret = ca_gtk_play_for_widget(GTK_WIDGET(d->object), 0,
CA_PROP_EVENT_ID, "window-close",
CA_PROP_EVENT_DESCRIPTION, "Window closed",
CA_PROP_CANBERRA_CACHE_CONTROL, "permanent",
NULL);
+ }
}
if (GTK_IS_WINDOW(d->object) && d->signal_id == signal_id_widget_window_state_event) {
GdkEventWindowState *e;
+ gboolean h, ph;
e = (GdkEventWindowState*) d->event;
- if ((e->changed_mask & GDK_WINDOW_STATE_ICONIFIED) && (e->new_window_state & GDK_WINDOW_STATE_ICONIFIED)) {
+ h = is_hidden(gdk_screen_get_display(gdk_event_get_screen(d->event)), e->window);
+ ph = !!g_object_get_qdata(d->object, was_hidden_quark);
+ g_object_set_qdata(d->object, was_hidden_quark, GINT_TO_POINTER(h));
+
+ if ((e->changed_mask & GDK_WINDOW_STATE_ICONIFIED) && (e->new_window_state & GDK_WINDOW_STATE_ICONIFIED) && h && !ph) {
ret = ca_gtk_play_for_widget(GTK_WIDGET(d->object), 0,
CA_PROP_EVENT_ID, "window-minimized",
@@ -338,7 +480,7 @@ static void dispatch_sound_event(SoundEventData *d) {
CA_PROP_CANBERRA_CACHE_CONTROL, "permanent",
NULL);
- } else if ((e->changed_mask & GDK_WINDOW_STATE_ICONIFIED) && !(e->new_window_state & GDK_WINDOW_STATE_ICONIFIED)) {
+ } else if ((e->changed_mask & GDK_WINDOW_STATE_ICONIFIED) && !(e->new_window_state & GDK_WINDOW_STATE_ICONIFIED) && ph) {
ret = ca_gtk_play_for_widget(GTK_WIDGET(d->object), 0,
CA_PROP_EVENT_ID, "window-unminimized",
@@ -357,7 +499,7 @@ static void dispatch_sound_event(SoundEventData *d) {
if (GTK_IS_CHECK_MENU_ITEM(d->object) && d->signal_id == signal_id_check_menu_item_toggled) {
- if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(d)))
+ if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(d->object)))
ret = ca_gtk_play_for_event(d->event, 0,
CA_PROP_EVENT_ID, "button-toggle-on",
CA_PROP_EVENT_DESCRIPTION, "Check menu item checked",
@@ -462,7 +604,15 @@ static void dispatch_sound_event(SoundEventData *d) {
NULL);
}
- if (GTK_IS_TREE_VIEW(d->object) && d->signal_id == signal_id_tree_view_move_cursor) {
+ if (GTK_IS_TREE_VIEW(d->object) && d->signal_id == signal_id_tree_view_cursor_changed) {
+ ret = ca_gtk_play_for_event(d->event, 0,
+ CA_PROP_EVENT_ID, "item-selected",
+ CA_PROP_EVENT_DESCRIPTION, "Item selected",
+ CA_PROP_CANBERRA_CACHE_CONTROL, "permanent",
+ NULL);
+ }
+
+ if (GTK_IS_ICON_VIEW(d->object) && d->signal_id == signal_id_icon_view_selection_changed) {
ret = ca_gtk_play_for_event(d->event, 0,
CA_PROP_EVENT_ID, "item-selected",
CA_PROP_EVENT_DESCRIPTION, "Item selected",
@@ -482,7 +632,9 @@ static gboolean idle_cb(void *userdata) {
g_message("idle_cb()");
while ((d = g_queue_pop_head(&sound_event_queue))) {
- d = filter_sound_event(d);
+
+ if (!(d = filter_sound_event(d)))
+ continue;
g_message("Dispatching signal %s on %s", g_signal_name(d->signal_id), g_type_name(G_OBJECT_TYPE(d->object)));
@@ -508,6 +660,11 @@ static gboolean emission_hook_cb(GSignalInvocationHint *hint, guint n_param_valu
!GTK_IS_WINDOW(object))
return TRUE;
+ if (hint->signal_id != signal_id_widget_hide &&
+ hint->signal_id != signal_id_dialog_response &&
+ !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)));
d = g_slice_new0(SoundEventData);
@@ -527,7 +684,7 @@ static gboolean emission_hook_cb(GSignalInvocationHint *hint, guint n_param_valu
d->arg1_is_set = TRUE;
}
- g_queue_push_tail(&sound_event_queue, e);
+ g_queue_push_tail(&sound_event_queue, d);
g_message("enqueuing");
@@ -551,6 +708,7 @@ static void install_hook(GType type, const char *signal, guint *sn) {
void gtk_module_init(gint *argc, gchar ***argv[]) {
/* This is the same quark libgnomeui uses! */
disable_sound_quark = g_quark_from_string("gnome_disable_sound_events");
+ was_hidden_quark = g_quark_from_string("canberra_was_hidden");
install_hook(GTK_TYPE_WINDOW, "show", &signal_id_widget_show);
install_hook(GTK_TYPE_WINDOW, "hide", &signal_id_widget_hide);
@@ -562,5 +720,6 @@ void gtk_module_init(gint *argc, gchar ***argv[]) {
install_hook(GTK_TYPE_BUTTON, "released", &signal_id_button_released);
install_hook(GTK_TYPE_WIDGET, "window-state-event", &signal_id_widget_window_state_event);
install_hook(GTK_TYPE_NOTEBOOK, "switch-page", &signal_id_notebook_switch_page);
- install_hook(GTK_TYPE_TREE_VIEW, "move-cursor", &signal_id_tree_view_move_cursor);
+ install_hook(GTK_TYPE_TREE_VIEW, "cursor-changed", &signal_id_tree_view_cursor_changed);
+ install_hook(GTK_TYPE_ICON_VIEW, "selection-changed", &signal_id_icon_view_selection_changed);
}
diff --git a/src/driver.h b/src/driver.h
index 732a5d4..43efbf4 100644
--- a/src/driver.h
+++ b/src/driver.h
@@ -35,4 +35,5 @@ int driver_play(ca_context *c, uint32_t id, ca_proplist *p, ca_finish_callback_t
int driver_cancel(ca_context *c, uint32_t id);
int driver_cache(ca_context *c, ca_proplist *p);
+
#endif
diff --git a/src/dso.c b/src/dso.c
index 5ff0fec..b8ed112 100644
--- a/src/dso.c
+++ b/src/dso.c
@@ -146,12 +146,42 @@ static int try_open(ca_context *c, const char *t) {
return CA_SUCCESS;
}
+static void* real_dlsym(lt_module m, const char *name, const char *symbol) {
+ char sn[256];
+ char *s;
+ void *r;
+
+ ca_return_null_if_fail(m);
+ ca_return_null_if_fail(name);
+ ca_return_null_if_fail(symbol);
+
+ snprintf(sn, sizeof(sn), "%s_%s", name, symbol);
+ sn[sizeof(sn)-1] = 0;
+
+ for (s = sn; *s; s++) {
+ if (*s >= 'a' && *s <= 'z')
+ continue;
+ if (*s >= 'A' && *s <= 'Z')
+ continue;
+ if (*s >= '0' && *s <= '9')
+ continue;
+
+ *s = '_';
+ }
+
+ if ((r = lt_dlsym(m, sn)))
+ return r;
+
+ return lt_dlsym(m, symbol);
+}
+
#define MAKE_FUNC_PTR(ret, args, x) ((ret (*) args ) (size_t) (x))
-#define GET_FUNC_PTR(module, name, ret, args) MAKE_FUNC_PTR(ret, args, lt_dlsym((module), (name)))
+#define GET_FUNC_PTR(module, name, symbol, ret, args) MAKE_FUNC_PTR(ret, args, real_dlsym((module), (name), (symbol)))
int driver_open(ca_context *c) {
int ret;
struct private_dso *p;
+ const char *driver;
ca_return_val_if_fail(c, CA_ERROR_INVALID);
ca_return_val_if_fail(!PRIVATE_DSO(c), CA_ERROR_STATE);
@@ -174,6 +204,8 @@ int driver_open(ca_context *c) {
return ret;
}
+ driver = c->driver;
+
} else {
const char *const * e;
@@ -195,17 +227,19 @@ int driver_open(ca_context *c) {
driver_destroy(c);
return CA_ERROR_NODRIVER;
}
+
+ driver = *e;
}
ca_assert(p->module);
- if (!(p->driver_open = GET_FUNC_PTR(p->module, "driver_open", int, (ca_context*))) ||
- !(p->driver_destroy = GET_FUNC_PTR(p->module, "driver_destroy", int, (ca_context*))) ||
- !(p->driver_change_device = GET_FUNC_PTR(p->module, "driver_change_device", int, (ca_context*, const char *device))) ||
- !(p->driver_change_props = GET_FUNC_PTR(p->module, "driver_change_props", int, (ca_context *, ca_proplist *changed, ca_proplist *merged))) ||
- !(p->driver_play = GET_FUNC_PTR(p->module, "driver_play", int, (ca_context*, uint32_t id, ca_proplist *p, ca_finish_callback_t cb, void *userdata))) ||
- !(p->driver_cancel = GET_FUNC_PTR(p->module, "driver_cancel", int, (ca_context*, uint32_t id))) ||
- !(p->driver_cache = GET_FUNC_PTR(p->module, "driver_cache", int, (ca_context*, ca_proplist *p)))) {
+ if (!(p->driver_open = GET_FUNC_PTR(p->module, driver, "driver_open", int, (ca_context*))) ||
+ !(p->driver_destroy = GET_FUNC_PTR(p->module, driver, "driver_destroy", int, (ca_context*))) ||
+ !(p->driver_change_device = GET_FUNC_PTR(p->module, driver, "driver_change_device", int, (ca_context*, const char *device))) ||
+ !(p->driver_change_props = GET_FUNC_PTR(p->module, driver, "driver_change_props", int, (ca_context *, ca_proplist *changed, ca_proplist *merged))) ||
+ !(p->driver_play = GET_FUNC_PTR(p->module, driver, "driver_play", int, (ca_context*, uint32_t id, ca_proplist *p, ca_finish_callback_t cb, void *userdata))) ||
+ !(p->driver_cancel = GET_FUNC_PTR(p->module, driver, "driver_cancel", int, (ca_context*, uint32_t id))) ||
+ !(p->driver_cache = GET_FUNC_PTR(p->module, driver, "driver_cache", int, (ca_context*, ca_proplist *p)))) {
driver_destroy(c);
return CA_ERROR_CORRUPT;
@@ -234,8 +268,10 @@ int driver_destroy(ca_context *c) {
if (p->module)
lt_dlclose(p->module);
- if (p->ltdl_initialized)
+ if (p->ltdl_initialized) {
lt_dlexit();
+ p->ltdl_initialized = FALSE;
+ }
ca_free(p);