From 899788b4c5e23af9dabfb98c5f864c2f933804f4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 30 Oct 2004 01:55:16 +0000 Subject: [PATCH] some updates for pa_hashmap add property infrastructure add module module-x11-publish allow ldpreloading of all modules abstract x11wrap from module-x11-bell git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@268 fefdeb5f-60dc-0310-8127-8f9354f1896f --- doc/todo | 9 ++ polyp/Makefile.am | 61 ++++++++- polyp/cli-command.c | 11 +- polyp/cli-text.c | 2 +- polyp/core.c | 5 + polyp/core.h | 2 +- polyp/hashmap.c | 19 ++- polyp/hashmap.h | 12 +- polyp/main.c | 4 +- polyp/module-alsa-sink.c | 1 + polyp/module-alsa-source.c | 1 + polyp/module-cli.c | 1 + polyp/module-combine.c | 1 + polyp/module-defs.h.m4 | 21 +++ polyp/module-esound-compat-spawnfd.c | 1 + polyp/module-esound-compat-spawnpid.c | 1 + polyp/module-match.c | 1 + polyp/module-native-protocol-fd.c | 1 + polyp/module-null-sink.c | 1 + polyp/module-oss-mmap.c | 1 + polyp/module-oss.c | 1 + polyp/module-pipe-sink.c | 1 + polyp/module-pipe-source.c | 1 + polyp/module-protocol-stub.c | 26 +++- polyp/module-sine.c | 1 + polyp/module-tunnel.c | 8 +- polyp/module-x11-bell.c | 84 +++++------- polyp/module-x11-publish.c | 167 ++++++++++++++++++++++++ polyp/module.h | 12 +- polyp/namereg.c | 6 +- polyp/polyplib-internal.h | 2 - polyp/props.c | 112 ++++++++++++++++ polyp/props.h | 55 ++++++++ polyp/protocol-native.c | 2 +- polyp/x11wrap.c | 235 ++++++++++++++++++++++++++++++++++ polyp/x11wrap.h | 52 ++++++++ 36 files changed, 829 insertions(+), 92 deletions(-) create mode 100644 polyp/module-defs.h.m4 create mode 100644 polyp/module-x11-publish.c create mode 100644 polyp/props.c create mode 100644 polyp/props.h create mode 100644 polyp/x11wrap.c create mode 100644 polyp/x11wrap.h diff --git a/doc/todo b/doc/todo index f2155b9..8212ea8 100644 --- a/doc/todo +++ b/doc/todo @@ -12,6 +12,15 @@ - add sync API - make most buffer sizes dependant on the sample type +- X11: support for the X11 synchronization extension +- X11: save auth info in root window +- pass meta info for hearing impaired +- fall back to getpwnam if $HOME doesn't exist +- module-match: look in $HOME for table +- limit all resources +- getaddrinfo +- add LGPL blurb to all concerning files + ** later *** - xmlrpc/http - dbus diff --git a/polyp/Makefile.am b/polyp/Makefile.am index ae551a1..d90d322 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -32,7 +32,7 @@ AM_CFLAGS+=-DPOLYPAUDIO_BINARY=\"$(bindir)/polypaudio\" AM_LDADD=$(PTHREAD_LIBS) -lm AM_LIBADD=$(PTHREAD_LIBS) -lm -EXTRA_DIST = default.pa.in daemon.conf.in client.conf.in depmod.py esdcompat.sh.in +EXTRA_DIST = default.pa.in daemon.conf.in client.conf.in depmod.py esdcompat.sh.in module-defs.h.m4 bin_PROGRAMS = polypaudio pacat pactl paplay bin_SCRIPTS = esdcompat.sh noinst_PROGRAMS = \ @@ -112,6 +112,33 @@ modlib_LTLIBRARIES= \ module-tunnel-source.la \ module-null-sink.la +SYMDEF_FILES= \ + module-cli-symdef.h \ + module-cli-protocol-tcp-symdef.h \ + module-cli-protocol-unix-symdef.h \ + module-pipe-sink-symdef.h \ + module-pipe-source-symdef.h \ + module-oss-symdef.h \ + module-oss-mmap-symdef.h \ + module-simple-protocol-tcp-symdef.h \ + module-simple-protocol-unix-symdef.h \ + module-esound-protocol-tcp-symdef.h \ + module-esound-protocol-unix-symdef.h \ + module-native-protocol-tcp-symdef.h \ + module-native-protocol-unix-symdef.h \ + module-native-protocol-fd-symdef.h \ + module-sine-symdef.h \ + module-combine-symdef.h \ + module-esound-compat-spawnfd-symdef.h \ + module-esound-compat-spawnpid-symdef.h \ + module-match-symdef.h \ + module-tunnel-sink-symdef.h \ + module-tunnel-source-symdef.h \ + module-null-sink-symdef.h + +EXTRA_DIST+=$(SYMDEF_FILES) +BUILT_SOURCES+=$(SYMDEF_FILES) + lib_LTLIBRARIES= \ libpolyp-@PA_MAJORMINOR@.la \ libpolyp-error-@PA_MAJORMINOR@.la \ @@ -167,12 +194,14 @@ polypaudio_SOURCES = idxset.c idxset.h \ daemon-conf.c daemon-conf.h \ dumpmodules.c dumpmodules.h \ conf-parser.h conf-parser.c \ - caps.h caps.c + caps.h caps.c \ + props.h props.c polypaudio_CFLAGS = $(AM_CFLAGS) $(LIBSAMPLERATE_CFLAGS) $(LIBSNDFILE_CFLAGS) polypaudio_INCLUDES = $(INCLTDL) polypaudio_LDADD = $(AM_LDADD) $(LIBLTDL) $(LIBSAMPLERATE_LIBS) $(LIBSNDFILE_LIBS) $(CAP_LIBS) -polypaudio_LDFLAGS=-export-dynamic +polypaudio_LDFLAGS= -export-dynamic -dlopen force +#-static $(foreach f,$(modlib_LTLIBRARIES),-dlpreopen $(f)) libprotocol_simple_la_SOURCES = protocol-simple.c protocol-simple.h libprotocol_simple_la_LDFLAGS = -avoid-version @@ -430,12 +459,28 @@ cpulimit_test2_LDADD = $(AM_LDADD) libpolyp-mainloop-@PA_MAJORMINOR@.la if HAVE_X11 modlib_LTLIBRARIES+= \ - module-x11-bell.la + libx11wrap.la \ + module-x11-bell.la \ + module-x11-publish.la +SYMDEF_FILES += \ + module-x11-bell-symdef.h \ + module-x11-publish-symdef.h + +libx11wrap_la_SOURCES = x11wrap.c x11wrap.h +libx11wrap_la_LDFLAGS = -avoid-version +libx11wrap_la_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS) +libx11wrap_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIB) module_x11_bell_la_SOURCES = module-x11-bell.c module_x11_bell_la_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS) module_x11_bell_la_LDFLAGS = -module -avoid-version -module_x11_bell_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIB) +module_x11_bell_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIB) libx11wrap.la + +module_x11_publish_la_SOURCES = module-x11-publish.c +module_x11_publish_la_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS) +module_x11_publish_la_LDFLAGS = -module -avoid-version +module_x11_publish_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIB) libx11wrap.la + endif ### ALSA modules @@ -445,6 +490,9 @@ modlib_LTLIBRARIES+= \ libalsa-util.la \ module-alsa-sink.la \ module-alsa-source.la +SYMDEF_FILES += \ + module-alsa-sink-symdef.h \ + module-alsa-source-symdef.h libalsa_util_la_SOURCES = alsa-util.c alsa-util.h libalsa_util_la_LDFLAGS = -avoid-version @@ -597,3 +645,6 @@ daemon.conf: daemon.conf.in Makefile install-exec-hook: chown root:root $(DESTDIR)$(bindir)/polypaudio chmod u+s $(DESTDIR)$(bindir)/polypaudio + +$(SYMDEF_FILES): module-defs.h.m4 + m4 -Dfname="$@" $< > $@ diff --git a/polyp/cli-command.c b/polyp/cli-command.c index 62981b4..d563a07 100644 --- a/polyp/cli-command.c +++ b/polyp/cli-command.c @@ -47,6 +47,7 @@ #include "autoload.h" #include "xmalloc.h" #include "sound-file-stream.h" +#include "props.h" struct command { const char *name; @@ -83,6 +84,7 @@ static int pa_cli_command_autoload_list(struct pa_core *c, struct pa_tokenizer * static int pa_cli_command_autoload_add(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose); static int pa_cli_command_autoload_remove(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose); static int pa_cli_command_dump(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose); +static int pa_cli_command_list_props(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose); static const struct command commands[] = { { "exit", pa_cli_command_exit, "Terminate the daemon", 1 }, @@ -118,6 +120,7 @@ static const struct command commands[] = { { "remove-autoload-sink", pa_cli_command_autoload_remove, "Remove autoload entry for a sink (args: name)", 2}, { "remove-autoload-source", pa_cli_command_autoload_remove, "Remove autoload entry for a source (args: name)", 2}, { "dump", pa_cli_command_dump, "Dump daemon configuration", 1}, + { "list-props", pa_cli_command_list_props, NULL, 1}, { NULL, NULL, NULL, 0 } }; @@ -602,6 +605,12 @@ static int pa_cli_command_autoload_list(struct pa_core *c, struct pa_tokenizer * return 0; } +static int pa_cli_command_list_props(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) { + assert(c && t); + pa_property_dump(c, buf); + return 0; +} + static int pa_cli_command_dump(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) { struct pa_module *m; struct pa_sink *s; @@ -654,7 +663,7 @@ static int pa_cli_command_dump(struct pa_core *c, struct pa_tokenizer *t, struct nl = 0; i = NULL; - while ((a = pa_hashmap_iterate(c->autoload_hashmap, &i))) { + while ((a = pa_hashmap_iterate(c->autoload_hashmap, &i, NULL))) { if (!nl) { pa_strbuf_puts(buf, "\n"); diff --git a/polyp/cli-text.c b/polyp/cli-text.c index c08b0d9..39f7b6e 100644 --- a/polyp/cli-text.c +++ b/polyp/cli-text.c @@ -271,7 +271,7 @@ char *pa_autoload_list_to_string(struct pa_core *c) { struct pa_autoload_entry *e; void *state = NULL; - while ((e = pa_hashmap_iterate(c->autoload_hashmap, &state))) { + while ((e = pa_hashmap_iterate(c->autoload_hashmap, &state, NULL))) { pa_strbuf_printf( s, " name: <%s>\n\ttype: <%s>\n\tindex: <%u>\n\tmodule_name: <%s>\n\targuments: <%s>\n", e->name, diff --git a/polyp/core.c b/polyp/core.c index c53d2e4..6e155dd 100644 --- a/polyp/core.c +++ b/polyp/core.c @@ -39,6 +39,7 @@ #include "autoload.h" #include "xmalloc.h" #include "subscribe.h" +#include "props.h" struct pa_core* pa_core_new(struct pa_mainloop_api *m) { struct pa_core* c; @@ -82,6 +83,8 @@ struct pa_core* pa_core_new(struct pa_mainloop_api *m) { c->scache_idle_time = 20; c->resample_method = SRC_SINC_FASTEST; + + pa_property_init(c); pa_check_signal_is_blocked(SIGPIPE); @@ -121,6 +124,8 @@ void pa_core_free(struct pa_core *c) { pa_xfree(c->default_sink_name); pa_memblock_stat_unref(c->memblock_stat); + + pa_property_cleanup(c); pa_xfree(c); } diff --git a/polyp/core.h b/polyp/core.h index c457c3f..1438bf7 100644 --- a/polyp/core.h +++ b/polyp/core.h @@ -33,7 +33,7 @@ struct pa_core { struct pa_idxset *clients, *sinks, *sources, *sink_inputs, *source_outputs, *modules, *scache, *autoload_idxset; - struct pa_hashmap *namereg, *autoload_hashmap; + struct pa_hashmap *namereg, *autoload_hashmap, *properties; char *default_source_name, *default_sink_name; diff --git a/polyp/hashmap.c b/polyp/hashmap.c index 2b9550f..10b148d 100644 --- a/polyp/hashmap.c +++ b/polyp/hashmap.c @@ -30,6 +30,7 @@ #include "hashmap.h" #include "idxset.h" #include "xmalloc.h" +#include "log.h" struct hashmap_entry { struct hashmap_entry *next, *previous, *bucket_next, *bucket_previous; @@ -147,25 +148,27 @@ void* pa_hashmap_get(struct pa_hashmap *h, const void *key) { return e->value; } -int pa_hashmap_remove(struct pa_hashmap *h, const void *key) { +void* pa_hashmap_remove(struct pa_hashmap *h, const void *key) { struct hashmap_entry *e; unsigned hash; + void *data; assert(h && key); hash = h->hash_func(key) % h->size; if (!(e = get(h, hash, key))) - return 1; + return NULL; + data = e->value; remove(h, e); - return 0; + return data; } unsigned pa_hashmap_ncontents(struct pa_hashmap *h) { return h->n_entries; } -void *pa_hashmap_iterate(struct pa_hashmap *h, void **state) { +void *pa_hashmap_iterate(struct pa_hashmap *h, void **state, const void **key) { assert(h && state); if (!*state) { @@ -173,8 +176,14 @@ void *pa_hashmap_iterate(struct pa_hashmap *h, void **state) { } else *state = ((struct hashmap_entry*) *state)->next; - if (!*state) + if (!*state) { + if (key) + *key = NULL; return NULL; + } + + if (key) + *key = ((struct hashmap_entry*) *state)->key; return ((struct hashmap_entry*) *state)->value; } diff --git a/polyp/hashmap.h b/polyp/hashmap.h index 3b79d7a..739f894 100644 --- a/polyp/hashmap.h +++ b/polyp/hashmap.h @@ -30,13 +30,15 @@ void pa_hashmap_free(struct pa_hashmap*, void (*free_func)(void *p, void *userda int pa_hashmap_put(struct pa_hashmap *h, const void *key, void *value); void* pa_hashmap_get(struct pa_hashmap *h, const void *key); -int pa_hashmap_remove(struct pa_hashmap *h, const void *key); +void* pa_hashmap_remove(struct pa_hashmap *h, const void *key); unsigned pa_hashmap_ncontents(struct pa_hashmap *h); -/* Maybe used to iterate through the hashmap. Initial state should - point to a NULL pointer. The hashmap may not be modified during - iteration */ -void *pa_hashmap_iterate(struct pa_hashmap *h, void **state); +/* May be used to iterate through the hashmap. Initially the opaque + pointer *state has to be set to NULL. The hashmap may not be + modified during iteration. The key of the entry is returned in + *key, if key is non-NULL. After the last entry in the hashmap NULL + is returned. */ +void *pa_hashmap_iterate(struct pa_hashmap *h, void **state, const void**key); #endif diff --git a/polyp/main.c b/polyp/main.c index 5be4118..378cb8a 100644 --- a/polyp/main.c +++ b/polyp/main.c @@ -152,9 +152,11 @@ int main(int argc, char *argv[]) { pa_drop_root(); } + LTDL_SET_PRELOADED_SYMBOLS(); + r = lt_dlinit(); assert(r == 0); - + pa_log_set_ident("polypaudio"); conf = pa_daemon_conf_new(); diff --git a/polyp/module-alsa-sink.c b/polyp/module-alsa-sink.c index 528fe8d..e319f6c 100644 --- a/polyp/module-alsa-sink.c +++ b/polyp/module-alsa-sink.c @@ -39,6 +39,7 @@ #include "alsa-util.h" #include "xmalloc.h" #include "log.h" +#include "module-alsa-sink-symdef.h" PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_DESCRIPTION("ALSA Sink") diff --git a/polyp/module-alsa-source.c b/polyp/module-alsa-source.c index c0a18d2..34f08f9 100644 --- a/polyp/module-alsa-source.c +++ b/polyp/module-alsa-source.c @@ -39,6 +39,7 @@ #include "alsa-util.h" #include "xmalloc.h" #include "log.h" +#include "module-alsa-source-symdef.h" PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_DESCRIPTION("ALSA Source") diff --git a/polyp/module-cli.c b/polyp/module-cli.c index 6444194..1ebc9b5 100644 --- a/polyp/module-cli.c +++ b/polyp/module-cli.c @@ -32,6 +32,7 @@ #include "cli.h" #include "sioman.h" #include "log.h" +#include "module-cli-symdef.h" PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_DESCRIPTION("Command line interface") diff --git a/polyp/module-combine.c b/polyp/module-combine.c index 1a90908..5df3f15 100644 --- a/polyp/module-combine.c +++ b/polyp/module-combine.c @@ -36,6 +36,7 @@ #include "xmalloc.h" #include "modargs.h" #include "namereg.h" +#include "module-combine-symdef.h" PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_DESCRIPTION("Combine multiple sinks to one") diff --git a/polyp/module-defs.h.m4 b/polyp/module-defs.h.m4 new file mode 100644 index 0000000..85eb64a --- /dev/null +++ b/polyp/module-defs.h.m4 @@ -0,0 +1,21 @@ +dnl $Id$ +changecom(`/*', `*/')dnl +define(`module', patsubst(patsubst(fname, `-symdef.h$'), `[^0-9a-zA-Z]', `_'))dnl +define(`c_symbol', patsubst(module, `[^0-9a-zA-Z]', `_'))dnl +define(`c_macro', patsubst(module, `[^0-9a-zA-Z]', `'))dnl +define(`incmacro', `foo'c_macro`symdeffoo')dnl +define(`gen_symbol', `#define $1 'module`_LTX_$1')dnl +#ifndef incmacro +#define incmacro + +gen_symbol(pa__init) +gen_symbol(pa__done) +gen_symbol(pa__get_author) +gen_symbol(pa__get_description) +gen_symbol(pa__get_usage) +gen_symbol(pa__get_version) + +int pa__init(struct pa_core *c, struct pa_module*m); +void pa__done(struct pa_core *c, struct pa_module*m); + +#endif diff --git a/polyp/module-esound-compat-spawnfd.c b/polyp/module-esound-compat-spawnfd.c index 514159f..ae4f909 100644 --- a/polyp/module-esound-compat-spawnfd.c +++ b/polyp/module-esound-compat-spawnfd.c @@ -32,6 +32,7 @@ #include "util.h" #include "modargs.h" #include "log.h" +#include "module-esound-compat-spawnfd-symdef.h" PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_DESCRIPTION("ESOUND compatibility module: -spawnfd emulation") diff --git a/polyp/module-esound-compat-spawnpid.c b/polyp/module-esound-compat-spawnpid.c index 5583f07..02756cd 100644 --- a/polyp/module-esound-compat-spawnpid.c +++ b/polyp/module-esound-compat-spawnpid.c @@ -32,6 +32,7 @@ #include "util.h" #include "modargs.h" #include "log.h" +#include "module-esound-compat-spawnpid-symdef.h" PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_DESCRIPTION("ESOUND compatibility module: -spawnpid emulation") diff --git a/polyp/module-match.c b/polyp/module-match.c index 380c601..6689cc5 100644 --- a/polyp/module-match.c +++ b/polyp/module-match.c @@ -39,6 +39,7 @@ #include "subscribe.h" #include "xmalloc.h" #include "sink-input.h" +#include "module-match-symdef.h" PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_DESCRIPTION("Sink input matching module") diff --git a/polyp/module-native-protocol-fd.c b/polyp/module-native-protocol-fd.c index c1ea697..8f41db6 100644 --- a/polyp/module-native-protocol-fd.c +++ b/polyp/module-native-protocol-fd.c @@ -32,6 +32,7 @@ #include "modargs.h" #include "protocol-native.h" #include "log.h" +#include "module-native-protocol-fd-symdef.h" PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_DESCRIPTION("Native protocol autospawn helper") diff --git a/polyp/module-null-sink.c b/polyp/module-null-sink.c index 8654201..4a41b74 100644 --- a/polyp/module-null-sink.c +++ b/polyp/module-null-sink.c @@ -40,6 +40,7 @@ #include "modargs.h" #include "xmalloc.h" #include "log.h" +#include "module-null-sink-symdef.h" PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_DESCRIPTION("Clocked NULL sink") diff --git a/polyp/module-oss-mmap.c b/polyp/module-oss-mmap.c index f7fcbd3..bc36d19 100644 --- a/polyp/module-oss-mmap.c +++ b/polyp/module-oss-mmap.c @@ -46,6 +46,7 @@ #include "modargs.h" #include "xmalloc.h" #include "log.h" +#include "module-oss-mmap-symdef.h" PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_DESCRIPTION("OSS Sink/Source (mmap)") diff --git a/polyp/module-oss.c b/polyp/module-oss.c index c0c6be8..969761f 100644 --- a/polyp/module-oss.c +++ b/polyp/module-oss.c @@ -45,6 +45,7 @@ #include "modargs.h" #include "xmalloc.h" #include "log.h" +#include "module-oss-symdef.h" PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_DESCRIPTION("OSS Sink/Source") diff --git a/polyp/module-pipe-sink.c b/polyp/module-pipe-sink.c index 7c779f7..bc8abb4 100644 --- a/polyp/module-pipe-sink.c +++ b/polyp/module-pipe-sink.c @@ -40,6 +40,7 @@ #include "modargs.h" #include "xmalloc.h" #include "log.h" +#include "module-pipe-sink-symdef.h" PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_DESCRIPTION("UNIX pipe sink") diff --git a/polyp/module-pipe-source.c b/polyp/module-pipe-source.c index 3decc41..8bc4c47 100644 --- a/polyp/module-pipe-source.c +++ b/polyp/module-pipe-source.c @@ -40,6 +40,7 @@ #include "modargs.h" #include "xmalloc.h" #include "log.h" +#include "module-pipe-source-symdef.h" PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_DESCRIPTION("UNIX pipe source") diff --git a/polyp/module-protocol-stub.c b/polyp/module-protocol-stub.c index 1ff70a1..8cef3bd 100644 --- a/polyp/module-protocol-stub.c +++ b/polyp/module-protocol-stub.c @@ -39,9 +39,6 @@ #include "log.h" #include "native-common.h" -PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_VERSION(PACKAGE_VERSION) - #ifdef USE_TCP_SOCKETS #define SOCKET_DESCRIPTION "(TCP sockets)" #define SOCKET_USAGE "port= loopback=" @@ -58,6 +55,11 @@ PA_MODULE_VERSION(PACKAGE_VERSION) #define IPV4_PORT 4711 #define UNIX_SOCKET "/tmp/polypaudio/simple" #define MODULE_ARGUMENTS "rate", "format", "channels", "sink", "source", "playback", "record", + #ifdef USE_TCP_SOCKETS + #include "module-simple-protocol-tcp-symdef.h" + #else + #include "module-simple-protocol-unix-symdef.h" + #endif PA_MODULE_DESCRIPTION("Simple protocol "SOCKET_DESCRIPTION) PA_MODULE_USAGE("rate= format= channels= sink= source= playback= record= "SOCKET_USAGE) #elif defined(USE_PROTOCOL_CLI) @@ -68,6 +70,11 @@ PA_MODULE_VERSION(PACKAGE_VERSION) #define IPV4_PORT 4712 #define UNIX_SOCKET "/tmp/polypaudio/cli" #define MODULE_ARGUMENTS + #ifdef USE_TCP_SOCKETS + #include "module-cli-protocol-tcp-symdef.h" + #else + #include "module-cli-protocol-unix-symdef.h" + #endif PA_MODULE_DESCRIPTION("Command line interface protocol "SOCKET_DESCRIPTION) PA_MODULE_USAGE(SOCKET_USAGE) #elif defined(USE_PROTOCOL_NATIVE) @@ -78,6 +85,11 @@ PA_MODULE_VERSION(PACKAGE_VERSION) #define IPV4_PORT PA_NATIVE_DEFAULT_PORT #define UNIX_SOCKET "/tmp/polypaudio/native" #define MODULE_ARGUMENTS "public", "cookie", + #ifdef USE_TCP_SOCKETS + #include "module-native-protocol-tcp-symdef.h" + #else + #include "module-native-protocol-unix-symdef.h" + #endif PA_MODULE_DESCRIPTION("Native protocol "SOCKET_DESCRIPTION) PA_MODULE_USAGE("public= cookie= "SOCKET_USAGE) #elif defined(USE_PROTOCOL_ESOUND) @@ -89,12 +101,20 @@ PA_MODULE_VERSION(PACKAGE_VERSION) #define IPV4_PORT ESD_DEFAULT_PORT #define UNIX_SOCKET ESD_UNIX_SOCKET_NAME #define MODULE_ARGUMENTS "sink", "source", "public", "cookie", + #ifdef USE_TCP_SOCKETS + #include "module-esound-protocol-tcp-symdef.h" + #else + #include "module-esound-protocol-unix-symdef.h" + #endif PA_MODULE_DESCRIPTION("EsounD protocol "SOCKET_DESCRIPTION) PA_MODULE_USAGE("sink= source= public= cookie= "SOCKET_USAGE) #else #error "Broken build system" #endif +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_VERSION(PACKAGE_VERSION) + static const char* const valid_modargs[] = { MODULE_ARGUMENTS #ifdef USE_TCP_SOCKETS diff --git a/polyp/module-sine.c b/polyp/module-sine.c index 458b878..393f929 100644 --- a/polyp/module-sine.c +++ b/polyp/module-sine.c @@ -33,6 +33,7 @@ #include "xmalloc.h" #include "namereg.h" #include "log.h" +#include "module-sine-symdef.h" PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_DESCRIPTION("Sine wave generator") diff --git a/polyp/module-tunnel.c b/polyp/module-tunnel.c index 1a720f3..2e22258 100644 --- a/polyp/module-tunnel.c +++ b/polyp/module-tunnel.c @@ -46,17 +46,19 @@ #include "socket-client.h" #include "socket-util.h" -PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_VERSION(PACKAGE_VERSION) - #ifdef TUNNEL_SINK +#include "module-tunnel-sink-symdef.h" PA_MODULE_DESCRIPTION("Tunnel module for sinks") PA_MODULE_USAGE("server= sink= cookie= format= channels= rate= sink_name=") #else +#include "module-tunnel-source-symdef.h" PA_MODULE_DESCRIPTION("Tunnel module for sources") PA_MODULE_USAGE("server= source= cookie= format= channels= rate= source_name=") #endif +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_VERSION(PACKAGE_VERSION) + #define DEFAULT_SINK_NAME "tunnel" #define DEFAULT_SOURCE_NAME "tunnel" diff --git a/polyp/module-x11-bell.c b/polyp/module-x11-bell.c index ae69f9c..23433c8 100644 --- a/polyp/module-x11-bell.c +++ b/polyp/module-x11-bell.c @@ -38,25 +38,23 @@ #include "xmalloc.h" #include "namereg.h" #include "log.h" +#include "x11wrap.h" +#include "module-x11-bell-symdef.h" PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_DESCRIPTION("X11 Bell interceptor") PA_MODULE_VERSION(PACKAGE_VERSION) PA_MODULE_USAGE("sink= sample= display=") -struct x11_source { - struct pa_io_event *io_event; - struct x11_source *next; -}; - struct userdata { struct pa_core *core; - Display *display; - struct x11_source *x11_sources; int xkb_event_base; - char *sink_name; char *scache_item; + Display *display; + + struct pa_x11_wrapper *x11_wrapper; + struct pa_x11_client *x11_client; }; static const char* const valid_modargs[] = { @@ -79,35 +77,22 @@ static int ring_bell(struct userdata *u, int percent) { return 0; } -static void io_callback(struct pa_mainloop_api*a, struct pa_io_event *e, int fd, enum pa_io_event_flags f, void *userdata) { +static int x11_event_callback(struct pa_x11_wrapper *w, XEvent *e, void *userdata) { + XkbBellNotifyEvent *bne; struct userdata *u = userdata; - assert(u); - - while (XPending(u->display)) { - XEvent e; - XkbBellNotifyEvent *bne; - XNextEvent(u->display, &e); - - if (((XkbEvent*) &e)->any.xkb_type != XkbBellNotify) - continue; - - bne = ((XkbBellNotifyEvent*) &e); - - if (ring_bell(u, bne->percent) < 0) { - pa_log(__FILE__": Ringing bell failed, reverting to X11 device bell.\n"); - XkbForceDeviceBell(u->display, bne->device, bne->bell_class, bne->bell_id, bne->percent); - } - } -} + assert(w && e && u && u->x11_wrapper == w); + + if (((XkbEvent*) e)->any.xkb_type != XkbBellNotify) + return 0; + + bne = (XkbBellNotifyEvent*) e; -static void new_io_source(struct userdata *u, int fd) { - struct x11_source *s; + if (ring_bell(u, bne->percent) < 0) { + pa_log(__FILE__": Ringing bell failed, reverting to X11 device bell.\n"); + XkbForceDeviceBell(pa_x11_wrapper_get_display(w), bne->device, bne->bell_class, bne->bell_id, bne->percent); + } - s = pa_xmalloc(sizeof(struct x11_source)); - s->io_event = u->core->mainloop->io_new(u->core->mainloop, fd, PA_IO_EVENT_INPUT, io_callback, u); - assert(s->io_event); - s->next = u->x11_sources; - u->x11_sources = s; + return 1; } int pa__init(struct pa_core *c, struct pa_module*m) { @@ -124,18 +109,15 @@ int pa__init(struct pa_core *c, struct pa_module*m) { m->userdata = u = pa_xmalloc(sizeof(struct userdata)); u->core = c; - u->display = NULL; - u->x11_sources = NULL; u->scache_item = pa_xstrdup(pa_modargs_get_value(ma, "sample", "x11-bell")); u->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL)); + u->x11_client = NULL; - if (!(u->display = XOpenDisplay(pa_modargs_get_value(ma, "display", NULL)))) { - pa_log(__FILE__": XOpenDisplay() failed\n"); + if (!(u->x11_wrapper = pa_x11_wrapper_get(c, pa_modargs_get_value(ma, "display", NULL)))) goto fail; - } - - new_io_source(u, ConnectionNumber(u->display)); + u->display = pa_x11_wrapper_get_display(u->x11_wrapper); + major = XkbMajorVersion; minor = XkbMinorVersion; @@ -147,6 +129,7 @@ int pa__init(struct pa_core *c, struct pa_module*m) { major = XkbMajorVersion; minor = XkbMinorVersion; + if (!XkbQueryExtension(u->display, NULL, &u->xkb_event_base, NULL, &major, &minor)) { pa_log(__FILE__": XkbQueryExtension() failed\n"); goto fail; @@ -157,6 +140,8 @@ int pa__init(struct pa_core *c, struct pa_module*m) { XkbSetAutoResetControls(u->display, XkbAudibleBellMask, &auto_ctrls, &auto_values); XkbChangeEnabledControls(u->display, XkbUseCoreKbd, XkbAudibleBellMask, 0); + u->x11_client = pa_x11_client_new(u->x11_wrapper, x11_event_callback, u); + pa_modargs_free(ma); return 0; @@ -173,17 +158,14 @@ void pa__done(struct pa_core *c, struct pa_module*m) { struct userdata *u = m->userdata; assert(c && m && u); - while (u->x11_sources) { - struct x11_source *s = u->x11_sources; - u->x11_sources = u->x11_sources->next; - c->mainloop->io_free(s->io_event); - pa_xfree(s); - } - pa_xfree(u->scache_item); pa_xfree(u->sink_name); - - if (u->display) - XCloseDisplay(u->display); + + if (u->x11_client) + pa_x11_client_free(u->x11_client); + + if (u->x11_wrapper) + pa_x11_wrapper_unref(u->x11_wrapper); + pa_xfree(u); } diff --git a/polyp/module-x11-publish.c b/polyp/module-x11-publish.c new file mode 100644 index 0000000..fd4df4a --- /dev/null +++ b/polyp/module-x11-publish.c @@ -0,0 +1,167 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio 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 polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include + +#include +#include + +#include "module.h" +#include "sink.h" +#include "scache.h" +#include "modargs.h" +#include "xmalloc.h" +#include "namereg.h" +#include "log.h" +#include "x11wrap.h" +#include "util.h" + +#include "module-x11-publish-symdef.h" + +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_DESCRIPTION("X11 Credential Publisher") +PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_USAGE("display=") + +static const char* const valid_modargs[] = { + "display", + "sink", + "source", + NULL +}; + +struct userdata { + struct pa_core *core; + struct pa_x11_wrapper *x11_wrapper; + Display *display; + char *id; +}; + +static void set_x11_prop(Display *d, const char *name, const char *data) { + Atom a = XInternAtom(d, name, False); + XChangeProperty(d, RootWindow(d, 0), a, XA_STRING, 8, PropModeReplace, (unsigned char*) data, strlen(data)+1); +} + +static void del_x11_prop(Display *d, const char *name) { + Atom a = XInternAtom(d, name, False); + XDeleteProperty(d, RootWindow(d, 0), a); +} + +static char* get_x11_prop(Display *d, const char *name, char *p, size_t l) { + Atom actual_type; + int actual_format; + unsigned long nitems; + unsigned long nbytes_after; + unsigned char *prop; + + Atom a = XInternAtom(d, name, False); + if (XGetWindowProperty(d, RootWindow(d, 0), a, 0, (l+2)/4, False, XA_STRING, &actual_type, &actual_format, &nitems, &nbytes_after, &prop) != Success) + return NULL; + + memcpy(p, prop, nitems); + p[nitems] = 0; + + XFree(prop); + return p; +} + +int pa__init(struct pa_core *c, struct pa_module*m) { + struct userdata *u; + struct pa_modargs *ma = NULL; + char hn[256], un[128]; + const char *t; + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + pa_log(__FILE__": failed to parse module arguments\n"); + goto fail; + } + + m->userdata = u = pa_xmalloc(sizeof(struct userdata)); + u->core = c; + u->id = NULL; + + if (!(u->x11_wrapper = pa_x11_wrapper_get(c, pa_modargs_get_value(ma, "display", NULL)))) + goto fail; + + u->display = pa_x11_wrapper_get_display(u->x11_wrapper); + + pa_get_host_name(hn, sizeof(hn)); + pa_get_user_name(un, sizeof(un)); + + u->id = pa_sprintf_malloc("%s@%s/%u", un, hn, (unsigned) getpid()); + + set_x11_prop(u->display, "POLYP_SERVER", hn); + set_x11_prop(u->display, "POLYP_ID", u->id); + + if ((t = pa_modargs_get_value(ma, "source", NULL))) + set_x11_prop(u->display, "POLYP_SOURCE", t); + + if ((t = pa_modargs_get_value(ma, "sink", NULL))) + set_x11_prop(u->display, "POLYP_SINK", t); + + pa_modargs_free(ma); + return 0; + +fail: + if (ma) + pa_modargs_free(ma); + + pa__done(c, m); + return -1; +} + +void pa__done(struct pa_core *c, struct pa_module*m) { + struct userdata*u; + assert(c && m); + + if (!(u = m->userdata)) + return; + + if (u->x11_wrapper) { + char t[256]; + + /* Yes, here is a race condition */ + if (!get_x11_prop(u->display, "POLYP_ID", t, sizeof(t)) || strcmp(t, u->id)) + pa_log("WARNING: Polypaudio information vanished from X11!\n"); + else { + del_x11_prop(u->display, "POLYP_ID"); + del_x11_prop(u->display, "POLYP_SERVER"); + del_x11_prop(u->display, "POLYP_SINK"); + del_x11_prop(u->display, "POLYP_SOURCE"); + XSync(u->display, False); + } + } + + if (u->x11_wrapper) + pa_x11_wrapper_unref(u->x11_wrapper); + + pa_xfree(u->id); + pa_xfree(u); +} + diff --git a/polyp/module.h b/polyp/module.h index f422132..7380f79 100644 --- a/polyp/module.h +++ b/polyp/module.h @@ -58,14 +58,10 @@ void pa_module_unload_request(struct pa_module *m); void pa_module_set_used(struct pa_module*m, int used); -/* prototypes for the module's entry points */ -int pa__init(struct pa_core *c, struct pa_module*m); -void pa__done(struct pa_core *c, struct pa_module*m); - -#define PA_MODULE_AUTHOR(s) const char *pa__get_author(void) { return s; } -#define PA_MODULE_DESCRIPTION(s) const char *pa__get_description(void) { return s; } -#define PA_MODULE_USAGE(s) const char *pa__get_usage(void) { return s; } -#define PA_MODULE_VERSION(s) const char *pa__get_version(void) { return s; } +#define PA_MODULE_AUTHOR(s) const char * pa__get_author(void) { return s; } +#define PA_MODULE_DESCRIPTION(s) const char * pa__get_description(void) { return s; } +#define PA_MODULE_USAGE(s) const char * pa__get_usage(void) { return s; } +#define PA_MODULE_VERSION(s) const char * pa__get_version(void) { return s; } struct pa_modinfo *pa_module_get_info(struct pa_module *m); diff --git a/polyp/namereg.c b/polyp/namereg.c index e2f65ef..cc25ea2 100644 --- a/polyp/namereg.c +++ b/polyp/namereg.c @@ -100,15 +100,11 @@ const char *pa_namereg_register(struct pa_core *c, const char *name, enum pa_nam void pa_namereg_unregister(struct pa_core *c, const char *name) { struct namereg_entry *e; - int r; assert(c && name); - e = pa_hashmap_get(c->namereg, name); + e = pa_hashmap_remove(c->namereg, name); assert(e); - r = pa_hashmap_remove(c->namereg, name); - assert(r >= 0); - pa_xfree(e->name); pa_xfree(e); } diff --git a/polyp/polyplib-internal.h b/polyp/polyplib-internal.h index e49b25d..623a89b 100644 --- a/polyp/polyplib-internal.h +++ b/polyp/polyplib-internal.h @@ -43,8 +43,6 @@ #define DEFAULT_TIMEOUT (10) -#define ENV_AUTOSPAWNED "POLYP_AUTOSPAWNED" - struct pa_context { int ref; diff --git a/polyp/props.c b/polyp/props.c new file mode 100644 index 0000000..014059e --- /dev/null +++ b/polyp/props.c @@ -0,0 +1,112 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio 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 polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +#include "xmalloc.h" +#include "props.h" +#include "log.h" + +struct pa_property { + char *name; /* Points to memory allocated by the property subsystem */ + void *data; /* Points to memory maintained by the caller */ +}; + +/* Allocate a new property object */ +static struct pa_property* property_new(const char *name, void *data) { + struct pa_property* p; + assert(name && data); + + p = pa_xmalloc(sizeof(struct pa_property)); + p->name = pa_xstrdup(name); + p->data = data; + + return p; +} + +/* Free a property object */ +static void property_free(struct pa_property *p) { + assert(p); + + pa_xfree(p->name); + pa_xfree(p); +} + +void* pa_property_get(struct pa_core *c, const char *name) { + struct pa_property *p; + assert(c && name && c->properties); + + if (!(p = pa_hashmap_get(c->properties, name))) + return NULL; + + return p->data; +} + +int pa_property_set(struct pa_core *c, const char *name, void *data) { + struct pa_property *p; + assert(c && name && data && c->properties); + + if (pa_hashmap_get(c->properties, name)) + return -1; + + p = property_new(name, data); + pa_hashmap_put(c->properties, p->name, p); + return 0; +} + +int pa_property_remove(struct pa_core *c, const char *name) { + struct pa_property *p; + assert(c && name && c->properties); + + if (!(p = pa_hashmap_remove(c->properties, name))) + return -1; + + property_free(p); + return 0; +} + +void pa_property_init(struct pa_core *c) { + assert(c); + + c->properties = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); +} + +void pa_property_cleanup(struct pa_core *c) { + assert(c); + + if (!c->properties) + return; + + assert(!pa_hashmap_ncontents(c->properties)); + + pa_hashmap_free(c->properties, NULL, NULL); + c->properties = NULL; + +} + +void pa_property_dump(struct pa_core *c, struct pa_strbuf *s) { + void *state = NULL; + struct pa_property *p; + assert(c && s); + + while ((p = pa_hashmap_iterate(c->properties, &state, NULL))) + pa_strbuf_printf(s, "[%s] -> [%p]\n", p->name, p->data); +} diff --git a/polyp/props.h b/polyp/props.h new file mode 100644 index 0000000..f19e926 --- /dev/null +++ b/polyp/props.h @@ -0,0 +1,55 @@ +#ifndef foopropshfoo +#define foopropshfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio 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 polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include "core.h" +#include "strbuf.h" + +/* The property subsystem is to be used to share data between + * modules. Consider them to be kind of "global" variables for a + * core. Why not use the hashmap functions directly? The hashmap + * functions copy neither the key nor value, while this property + * system copies the key. Users of this system have to think about + * reference counting themselves. */ + +/* Return a pointer to the value of the specified property. */ +void* pa_property_get(struct pa_core *c, const char *name); + +/* Set the property 'name' to 'data'. This function fails in case a + * property by this name already exists. The property data is not + * copied or reference counted. This is the caller's job. */ +int pa_property_set(struct pa_core *c, const char *name, void *data); + +/* Remove the specified property. Return non-zero on failure */ +int pa_property_remove(struct pa_core *c, const char *name); + +/* Free all memory used by the property system */ +void pa_property_cleanup(struct pa_core *c); + +/* Initialize the properties subsystem */ +void pa_property_init(struct pa_core *c); + +/* Dump the current set of properties */ +void pa_property_dump(struct pa_core *c, struct pa_strbuf *s); + +#endif diff --git a/polyp/protocol-native.c b/polyp/protocol-native.c index 7af8bdd..6f3f82b 100644 --- a/polyp/protocol-native.c +++ b/polyp/protocol-native.c @@ -1869,7 +1869,7 @@ static void command_get_autoload_info_list(struct pa_pdispatch *pd, uint32_t com struct pa_autoload_entry *a; void *state = NULL; - while ((a = pa_hashmap_iterate(c->protocol->core->autoload_hashmap, &state))) + while ((a = pa_hashmap_iterate(c->protocol->core->autoload_hashmap, &state, NULL))) autoload_fill_tagstruct(reply, a); } diff --git a/polyp/x11wrap.c b/polyp/x11wrap.c new file mode 100644 index 0000000..a1a9732 --- /dev/null +++ b/polyp/x11wrap.c @@ -0,0 +1,235 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio 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 polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include + +#include "llist.h" +#include "x11wrap.h" +#include "xmalloc.h" +#include "log.h" +#include "props.h" + +struct pa_x11_client; + +struct pa_x11_internal { + PA_LLIST_FIELDS(struct pa_x11_internal); + struct pa_x11_wrapper *wrapper; + struct pa_io_event* io_event; + int fd; +}; + +struct pa_x11_wrapper { + struct pa_core *core; + int ref; + + char *property_name; + Display *display; + + struct pa_defer_event* defer_event; + struct pa_io_event* io_event; + + PA_LLIST_HEAD(struct pa_x11_client, clients); + PA_LLIST_HEAD(struct pa_x11_internal, internals); +}; + +struct pa_x11_client { + PA_LLIST_FIELDS(struct pa_x11_client); + struct pa_x11_wrapper *wrapper; + int (*callback)(struct pa_x11_wrapper *w, XEvent *e, void *userdata); + void *userdata; +}; + +/* Dispatch all pending X11 events */ +static void work(struct pa_x11_wrapper *w) { + assert(w && w->ref >= 1); + + while (XPending(w->display)) { + struct pa_x11_client *c; + XEvent e; + XNextEvent(w->display, &e); + + for (c = w->clients; c; c = c->next) { + assert(c->callback); + if (c->callback(w, &e, c->userdata) != 0) + break; + } + } +} + +/* IO notification event for the X11 display connection */ +static void display_io_event(struct pa_mainloop_api *m, struct pa_io_event *e, int fd, enum pa_io_event_flags f, void *userdata) { + struct pa_x11_wrapper *w = userdata; + assert(m && e && fd >= 0 && w && w->ref >= 1); + work(w); +} + +/* Deferred notification event. Called once each main loop iteration */ +static void defer_event(struct pa_mainloop_api *m, struct pa_defer_event *e, void *userdata) { + struct pa_x11_wrapper *w = userdata; + assert(m && e && w && w->ref >= 1); + work(w); +} + +/* IO notification event for X11 internal connections */ +static void internal_io_event(struct pa_mainloop_api *m, struct pa_io_event *e, int fd, enum pa_io_event_flags f, void *userdata) { + struct pa_x11_wrapper *w = userdata; + assert(m && e && fd >= 0 && w && w->ref >= 1); + + XProcessInternalConnection(w->display, fd); +} + +/* Add a new IO source for the specified X11 internal connection */ +static struct pa_x11_internal* x11_internal_add(struct pa_x11_wrapper *w, int fd) { + struct pa_x11_internal *i; + assert(i && fd >= 0); + + i = pa_xmalloc(sizeof(struct pa_x11_internal)); + i->wrapper = w; + i->io_event = w->core->mainloop->io_new(w->core->mainloop, fd, PA_IO_EVENT_INPUT, internal_io_event, w); + i->fd = fd; + + PA_LLIST_PREPEND(struct pa_x11_internal, w->internals, i); + return i; +} + +/* Remove an IO source for an X11 internal connection */ +void x11_internal_remove(struct pa_x11_wrapper *w, struct pa_x11_internal *i) { + assert(i); + + PA_LLIST_REMOVE(struct pa_x11_internal, w->internals, i); + w->core->mainloop->io_free(i->io_event); + pa_xfree(i); +} + +/* Implementation of XConnectionWatchProc */ +static void x11_watch(Display *display, XPointer userdata, int fd, Bool opening, XPointer *watch_data) { + struct pa_x11_wrapper *w = (struct pa_x11_wrapper*) userdata; + assert(display && w && fd >= 0); + + if (opening) + *watch_data = (XPointer) x11_internal_add(w, fd); + else + x11_internal_remove(w, (struct pa_x11_internal*) *watch_data); +} + +static struct pa_x11_wrapper* x11_wrapper_new(struct pa_core *c, const char *name, const char *t) { + struct pa_x11_wrapper*w; + Display *d; + int r; + + if (!(d = XOpenDisplay(name))) { + pa_log(__FILE__": XOpenDisplay() failed\n"); + return NULL; + } + + w = pa_xmalloc(sizeof(struct pa_x11_wrapper)); + w->core = c; + w->ref = 1; + w->property_name = pa_xstrdup(t); + w->display = d; + + PA_LLIST_HEAD_INIT(struct pa_x11_client, w->clients); + PA_LLIST_HEAD_INIT(struct pa_x11_internal, w->internals); + + w->defer_event = c->mainloop->defer_new(c->mainloop, defer_event, w); + w->io_event = c->mainloop->io_new(c->mainloop, ConnectionNumber(d), PA_IO_EVENT_INPUT, display_io_event, w); + + XAddConnectionWatch(d, x11_watch, (XPointer) w); + + r = pa_property_set(c, w->property_name, w); + assert(r >= 0); + + return w; +} + +static void x11_wrapper_free(struct pa_x11_wrapper*w) { + int r; + assert(w); + + r = pa_property_remove(w->core, w->property_name); + assert(r >= 0); + + assert(!w->clients); + + XRemoveConnectionWatch(w->display, x11_watch, (XPointer) w); + XCloseDisplay(w->display); + + w->core->mainloop->io_free(w->io_event); + w->core->mainloop->defer_free(w->defer_event); + + while (w->internals) + x11_internal_remove(w, w->internals); + + pa_xfree(w->property_name); + pa_xfree(w); +} + +struct pa_x11_wrapper* pa_x11_wrapper_get(struct pa_core *c, const char *name) { + char t[256]; + struct pa_x11_wrapper *w; + assert(c); + + snprintf(t, sizeof(t), "x11-wrapper%s%s", name ? "-" : "", name ? name : ""); + if ((w = pa_property_get(c, t))) + return pa_x11_wrapper_ref(w); + + return x11_wrapper_new(c, name, t); +} + +struct pa_x11_wrapper* pa_x11_wrapper_ref(struct pa_x11_wrapper *w) { + assert(w && w->ref >= 1); + w->ref++; + return w; +} + +void pa_x11_wrapper_unref(struct pa_x11_wrapper* w) { + assert(w && w->ref >= 1); + + if (!(--w->ref)) + x11_wrapper_free(w); +} + +Display *pa_x11_wrapper_get_display(struct pa_x11_wrapper *w) { + assert(w && w->ref >= 1); + return w->display; +} + +struct pa_x11_client* pa_x11_client_new(struct pa_x11_wrapper *w, int (*cb)(struct pa_x11_wrapper *w, XEvent *e, void *userdata), void *userdata) { + struct pa_x11_client *c; + assert(w && w->ref >= 1); + + c = pa_xmalloc(sizeof(struct pa_x11_client)); + c->wrapper = w; + c->callback = cb; + c->userdata = userdata; + + PA_LLIST_PREPEND(struct pa_x11_client, w->clients, c); + + return c; +} + +void pa_x11_client_free(struct pa_x11_client *c) { + assert(c && c->wrapper && c->wrapper->ref >= 1); + + PA_LLIST_REMOVE(struct pa_x11_client, c->wrapper->clients, c); + pa_xfree(c); +} diff --git a/polyp/x11wrap.h b/polyp/x11wrap.h new file mode 100644 index 0000000..79c6901 --- /dev/null +++ b/polyp/x11wrap.h @@ -0,0 +1,52 @@ +#ifndef foox11wraphfoo +#define foox11wraphfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio 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 polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +#include "core.h" + +struct pa_x11_wrapper; + +/* Return the X11 wrapper for this core. In case no wrapper was + existant before, allocate a new one */ +struct pa_x11_wrapper* pa_x11_wrapper_get(struct pa_core *c, const char *name); + +/* Increase the wrapper's reference count by one */ +struct pa_x11_wrapper* pa_x11_wrapper_ref(struct pa_x11_wrapper *w); + +/* Decrease the reference counter of an X11 wrapper object */ +void pa_x11_wrapper_unref(struct pa_x11_wrapper* w); + +/* Return the X11 display object for this connection */ +Display *pa_x11_wrapper_get_display(struct pa_x11_wrapper *w); + +struct pa_x11_client; + +/* Register an X11 client, that is called for each X11 event */ +struct pa_x11_client* pa_x11_client_new(struct pa_x11_wrapper *w, int (*cb)(struct pa_x11_wrapper *w, XEvent *e, void *userdata), void *userdata); + +/* Free an X11 client object */ +void pa_x11_client_free(struct pa_x11_client *c); + +#endif -- 2.7.4