diff options
36 files changed, 829 insertions, 92 deletions
@@ -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 ae551a1b..d90d3229 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 62981b4d..d563a072 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 c08b0d9c..39f7b6ed 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 c53d2e4e..6e155dda 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 c457c3fd..1438bf72 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 2b9550fd..10b148dd 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 3b79d7ae..739f8947 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 5be4118d..378cb8a0 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 528fe8d3..e319f6c1 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 c0a18d2b..34f08f95 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 6444194c..1ebc9b52 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 1a909087..5df3f158 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 00000000..85eb64a2 --- /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 514159fc..ae4f9095 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 5583f071..02756cdb 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 380c6011..6689cc59 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 c1ea6975..8f41db64 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 86542010..4a41b74d 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 f7fcbd3b..bc36d199 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 c0c6be8e..969761f6 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 7c779f7d..bc8abb41 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 3decc415..8bc4c477 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 1ff70a1a..8cef3bdb 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=<TCP port number> loopback=<listen on loopback device only?>" @@ -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=<sample rate> format=<sample format> channels=<number of channels> sink=<sink to connect to> source=<source to connect to> playback=<enable playback?> record=<enable 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=<don't check for cookies?> cookie=<path to cookie file> "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=<sink to connect to> source=<source to connect to> public=<don't check for cookies?> cookie=<path to cookie file> "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 458b8788..393f929a 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 1a720f3b..2e22258a 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=<filename> sink=<remote sink name> cookie=<filename> format=<sample format> channels=<number of channels> rate=<sample rate> sink_name=<name for the local sink>")  #else +#include "module-tunnel-source-symdef.h"  PA_MODULE_DESCRIPTION("Tunnel module for sources")  PA_MODULE_USAGE("server=<filename> source=<remote source name> cookie=<filename> format=<sample format> channels=<number of channels> rate=<sample rate> source_name=<name for the local source>")  #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 ae69f9cb..23433c8f 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=<sink to connect to> sample=<sample name> display=<X11 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 00000000..fd4df4ad --- /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 <config.h> +#endif + +#include <stdio.h> +#include <assert.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <X11/Xlib.h> +#include <X11/Xatom.h> + +#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=<X11 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 f422132a..7380f795 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 e2f65efd..cc25ea2b 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 e49b25d4..623a89b3 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 00000000..014059ec --- /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 <assert.h> + +#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 00000000..f19e9260 --- /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 7af8bdda..6f3f82be 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 00000000..a1a9732a --- /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 <assert.h> +#include <stdio.h> + +#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 00000000..79c69015 --- /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 <X11/Xlib.h> + +#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  | 
