From d9e44c52cb05df1134087865b1e18de8884af75b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 9 Aug 2007 23:47:06 +0000 Subject: [PATCH] Add X11 XSMP module for hooking into the X11 session manager, for being notified about X11 disconnects before they actually happen, so that we are not killed by the bloody xlibs git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/lennart@1610 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 9 +- src/daemon/default.pa.in | 3 + src/modules/module-x11-xsmp.c | 201 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 212 insertions(+), 1 deletion(-) create mode 100644 src/modules/module-x11-xsmp.c diff --git a/src/Makefile.am b/src/Makefile.am index bea5866..5edd200 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -924,7 +924,8 @@ endif if HAVE_X11 modlibexec_LTLIBRARIES += \ module-x11-bell.la \ - module-x11-publish.la + module-x11-publish.la \ + module-x11-xsmp.la endif if HAVE_OSS @@ -1016,6 +1017,7 @@ SYMDEF_FILES = \ modules/module-http-protocol-unix-symdef.h \ modules/module-x11-bell-symdef.h \ modules/module-x11-publish-symdef.h \ + modules/module-x11-xsmp-symdef.h \ modules/module-oss-symdef.h \ modules/module-alsa-sink-symdef.h \ modules/module-alsa-source-symdef.h \ @@ -1173,6 +1175,11 @@ 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_LIBS) libx11wrap.la libauthkey.la libauthkey-prop.la libx11prop.la libstrlist.la libpulsecore.la +module_x11_xsmp_la_SOURCES = modules/module-x11-xsmp.c +module_x11_xsmp_la_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS) +module_x11_xsmp_la_LDFLAGS = -module -avoid-version +module_x11_xsmp_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS) libpulsecore.la + # OSS liboss_util_la_SOURCES = modules/oss-util.c modules/oss-util.h diff --git a/src/daemon/default.pa.in b/src/daemon/default.pa.in index 63ae82c..583b26c 100755 --- a/src/daemon/default.pa.in +++ b/src/daemon/default.pa.in @@ -76,6 +76,9 @@ load-module module-x11-bell sample=x11-bell ### Publish connection data in the X11 root window load-module module-x11-publish +### Register ourselves in the X11 session manager +load-module module-x11-xsmp + ### Load additional modules from GConf settings. This can be configured with the paprefs tool. ### Please keep in mind that the modules configured by paprefs might conflict with manually ### loaded modules. diff --git a/src/modules/module-x11-xsmp.c b/src/modules/module-x11-xsmp.c new file mode 100644 index 0000000..dc23ebe --- /dev/null +++ b/src/modules/module-x11-xsmp.c @@ -0,0 +1,201 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + Copyright 2004-2006 Lennart Poettering + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio 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 Lesser General Public License + along with PulseAudio; 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 +#include +#include +#include +#include +#include +#include + +#include "module-x11-xsmp-symdef.h" + +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_DESCRIPTION("X11 session management") +PA_MODULE_VERSION(PACKAGE_VERSION) + +struct userdata { + pa_core *core; + SmcConn sm_conn; +}; + +static const char* const valid_modargs[] = { + NULL +}; + +static void die_cb(SmcConn connection, SmPointer client_data){ + pa_core *c = client_data; + + pa_log_debug("Got die message from XSM. Exiting..."); + + pa_core_assert_ref(c); + c->mainloop->quit(c->mainloop, 0); +} + +static void save_complete_cb(SmcConn connection, SmPointer client_data) { +} + +static void shutdown_cancelled_cb(SmcConn connection, SmPointer client_data) { + SmcSaveYourselfDone(connection, True); +} + +static void save_yourself_cb(SmcConn connection, SmPointer client_data, int save_type, Bool _shutdown, int interact_style, Bool fast) { + SmcSaveYourselfDone(connection, True); +} + +static void ice_io_cb(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t flags, void *userdata) { + IceConn connection = userdata; + + if (IceProcessMessages(connection, NULL, NULL) == IceProcessMessagesIOError) { + IceSetShutdownNegotiation(connection, False); + IceCloseConnection(connection); + } +} + +static void new_ice_connection(IceConn connection, IcePointer client_data, Bool opening, IcePointer *watch_data) { + pa_core *c = client_data; + + pa_assert(c); + + if (opening) + *watch_data = c->mainloop->io_new(c->mainloop, IceConnectionNumber(connection), PA_IO_EVENT_INPUT, ice_io_cb, connection); + else + c->mainloop->io_free(*watch_data); +} + +int pa__init(pa_core *c, pa_module*m) { + struct userdata *u = NULL; + pa_modargs *ma = NULL; + char t[256], *vendor, *client_id; + SmcCallbacks callbacks; + SmProp prop_program, prop_user; + SmProp *prop_list[2]; + SmPropValue val_program, val_user; + + pa_assert(c); + pa_assert(m); + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + pa_log("Failed to parse module arguments"); + goto fail; + } + + if (!getenv("SESSION_MANAGER")) { + pa_log("X11 session manager not running."); + goto fail; + } + + m->userdata = u = pa_xnew(struct userdata, 1); + u->core = c; + u->sm_conn = NULL; + + IceAddConnectionWatch(new_ice_connection, c); + + memset(&callbacks, 0, sizeof(callbacks)); + callbacks.die.callback = die_cb; + callbacks.die.client_data = c; + + callbacks.save_yourself.callback = save_yourself_cb; + callbacks.save_complete.callback = save_complete_cb; + callbacks.shutdown_cancelled.callback = shutdown_cancelled_cb; + + if (!(u->sm_conn = SmcOpenConnection( + NULL, u, + SmProtoMajor, SmProtoMinor, + SmcSaveYourselfProcMask | SmcDieProcMask | SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask, + &callbacks, NULL, &client_id, + sizeof(t), t))) { + + pa_log("Failed to open connection to session manager: %s", t); + goto fail; + } + + prop_program.name = (char*) SmProgram; + prop_program.type = (char*) SmARRAY8; + val_program.value = (char*) PACKAGE_NAME; + val_program.length = strlen(val_program.value); + prop_program.num_vals = 1; + prop_program.vals = &val_program; + prop_list[0] = &prop_program; + + prop_user.name = (char*) SmUserID; + prop_user.type = (char*) SmARRAY8; + pa_get_user_name(t, sizeof(t)); + val_user.value = t; + val_user.length = strlen(val_user.value); + prop_user.num_vals = 1; + prop_user.vals = &val_user; + prop_list[1] = &prop_user; + + SmcSetProperties(u->sm_conn, PA_ELEMENTSOF(prop_list), prop_list); + + pa_log_info("Connected to session manager '%s' as '%s'.", vendor = SmcVendor(u->sm_conn), client_id); + free(vendor); + free(client_id); + + pa_modargs_free(ma); + + return 0; + +fail: + if (ma) + pa_modargs_free(ma); + + pa__done(c, m); + + return -1; +} + +void pa__done(pa_core *c, pa_module*m) { + struct userdata *u; + + assert(c); + assert(m); + + if (!m->userdata) + return; + + u = m->userdata; + + if (u->sm_conn) + SmcCloseConnection(u->sm_conn, 0, NULL); + + IceRemoveConnectionWatch(new_ice_connection, c); + + pa_xfree(u); +} -- 2.7.4