]> code.delx.au - pulseaudio/blob - src/modules/x11/module-x11-xsmp.c
47a4e93e997ec8531051299eb68a347db05459c3
[pulseaudio] / src / modules / x11 / module-x11-xsmp.c
1 /***
2 This file is part of PulseAudio.
3
4 Copyright 2004-2006 Lennart Poettering
5
6 PulseAudio is free software; you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as published
8 by the Free Software Foundation; either version 2.1 of the License,
9 or (at your option) any later version.
10
11 PulseAudio is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with PulseAudio; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19 USA.
20 ***/
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29
30 #include <X11/Xlib.h>
31 #include <X11/SM/SMlib.h>
32
33 #include <pulse/xmalloc.h>
34 #include <pulse/util.h>
35
36 #include <pulsecore/iochannel.h>
37 #include <pulsecore/sink.h>
38 #include <pulsecore/core-scache.h>
39 #include <pulsecore/modargs.h>
40 #include <pulsecore/namereg.h>
41 #include <pulsecore/log.h>
42 #include <pulsecore/core-util.h>
43 #include <pulsecore/x11wrap.h>
44
45 #include "module-x11-xsmp-symdef.h"
46
47 PA_MODULE_AUTHOR("Lennart Poettering");
48 PA_MODULE_DESCRIPTION("X11 session management");
49 PA_MODULE_VERSION(PACKAGE_VERSION);
50 PA_MODULE_LOAD_ONCE(FALSE);
51 PA_MODULE_USAGE("session_manager=<session manager string> display=<X11 display>");
52
53 static pa_bool_t ice_in_use = FALSE;
54
55 static const char* const valid_modargs[] = {
56 "session_manager",
57 "display",
58 NULL
59 };
60
61 struct userdata {
62 pa_core *core;
63 pa_module *module;
64 pa_client *client;
65 SmcConn connection;
66 pa_x11_wrapper *x11;
67 };
68
69 static void die_cb(SmcConn connection, SmPointer client_data){
70 struct userdata *u = client_data;
71 pa_assert(u);
72
73 pa_log_debug("Got die message from XSMP.");
74
75 pa_x11_wrapper_kill(u->x11);
76
77 pa_x11_wrapper_unref(u->x11);
78 u->x11 = NULL;
79
80 pa_module_unload_request(u->module, TRUE);
81 }
82
83 static void save_complete_cb(SmcConn connection, SmPointer client_data) {
84 }
85
86 static void shutdown_cancelled_cb(SmcConn connection, SmPointer client_data) {
87 SmcSaveYourselfDone(connection, True);
88 }
89
90 static void save_yourself_cb(SmcConn connection, SmPointer client_data, int save_type, Bool _shutdown, int interact_style, Bool fast) {
91 SmcSaveYourselfDone(connection, True);
92 }
93
94 static void ice_io_cb(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t flags, void *userdata) {
95 IceConn connection = userdata;
96
97 if (IceProcessMessages(connection, NULL, NULL) == IceProcessMessagesIOError) {
98 IceSetShutdownNegotiation(connection, False);
99 IceCloseConnection(connection);
100 }
101 }
102
103 static void new_ice_connection(IceConn connection, IcePointer client_data, Bool opening, IcePointer *watch_data) {
104 struct pa_core *c = client_data;
105
106 if (opening)
107 *watch_data = c->mainloop->io_new(
108 c->mainloop,
109 IceConnectionNumber(connection),
110 PA_IO_EVENT_INPUT,
111 ice_io_cb,
112 connection);
113 else
114 c->mainloop->io_free(*watch_data);
115 }
116
117 int pa__init(pa_module*m) {
118
119 pa_modargs *ma = NULL;
120 char t[256], *vendor, *client_id;
121 SmcCallbacks callbacks;
122 SmProp prop_program, prop_user;
123 SmProp *prop_list[2];
124 SmPropValue val_program, val_user;
125 struct userdata *u;
126 const char *e;
127 pa_client_new_data data;
128
129 pa_assert(m);
130
131 if (ice_in_use) {
132 pa_log("module-x11-xsmp may not be loaded twice.");
133 return -1;
134 }
135
136 IceAddConnectionWatch(new_ice_connection, m->core);
137 ice_in_use = TRUE;
138
139 m->userdata = u = pa_xnew(struct userdata, 1);
140 u->core = m->core;
141 u->module = m;
142 u->client = NULL;
143 u->connection = NULL;
144 u->x11 = NULL;
145
146 if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
147 pa_log("Failed to parse module arguments");
148 goto fail;
149 }
150
151 if (!(u->x11 = pa_x11_wrapper_get(m->core, pa_modargs_get_value(ma, "display", NULL))))
152 goto fail;
153
154 e = pa_modargs_get_value(ma, "session_manager", NULL);
155
156 if (!e && !getenv("SESSION_MANAGER")) {
157 pa_log("X11 session manager not running.");
158 goto fail;
159 }
160
161 memset(&callbacks, 0, sizeof(callbacks));
162 callbacks.die.callback = die_cb;
163 callbacks.die.client_data = u;
164 callbacks.save_yourself.callback = save_yourself_cb;
165 callbacks.save_yourself.client_data = m->core;
166 callbacks.save_complete.callback = save_complete_cb;
167 callbacks.save_complete.client_data = m->core;
168 callbacks.shutdown_cancelled.callback = shutdown_cancelled_cb;
169 callbacks.shutdown_cancelled.client_data = m->core;
170
171 if (!(u->connection = SmcOpenConnection(
172 (char*) e, m->core,
173 SmProtoMajor, SmProtoMinor,
174 SmcSaveYourselfProcMask | SmcDieProcMask | SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask,
175 &callbacks, NULL, &client_id,
176 sizeof(t), t))) {
177
178 pa_log("Failed to open connection to session manager: %s", t);
179 goto fail;
180 }
181
182 prop_program.name = (char*) SmProgram;
183 prop_program.type = (char*) SmARRAY8;
184 val_program.value = (char*) PACKAGE_NAME;
185 val_program.length = (int) strlen(val_program.value);
186 prop_program.num_vals = 1;
187 prop_program.vals = &val_program;
188 prop_list[0] = &prop_program;
189
190 prop_user.name = (char*) SmUserID;
191 prop_user.type = (char*) SmARRAY8;
192 pa_get_user_name(t, sizeof(t));
193 val_user.value = t;
194 val_user.length = (int) strlen(val_user.value);
195 prop_user.num_vals = 1;
196 prop_user.vals = &val_user;
197 prop_list[1] = &prop_user;
198
199 SmcSetProperties(u->connection, PA_ELEMENTSOF(prop_list), prop_list);
200
201 pa_log_info("Connected to session manager '%s' as '%s'.", vendor = SmcVendor(u->connection), client_id);
202
203 pa_client_new_data_init(&data);
204 data.module = m;
205 data.driver = __FILE__;
206 pa_proplist_setf(data.proplist, PA_PROP_APPLICATION_NAME, "XSMP Session on %s as %s", vendor, client_id);
207 pa_proplist_sets(data.proplist, "xsmp.vendor", vendor);
208 pa_proplist_sets(data.proplist, "xsmp.client.id", client_id);
209 u->client = pa_client_new(u->core, &data);
210 pa_client_new_data_done(&data);
211
212 free(vendor);
213 free(client_id);
214
215 if (!u->client)
216 goto fail;
217
218 pa_modargs_free(ma);
219
220 return 0;
221
222 fail:
223 if (ma)
224 pa_modargs_free(ma);
225
226 pa__done(m);
227
228 return -1;
229 }
230
231 void pa__done(pa_module*m) {
232 struct userdata *u;
233
234 pa_assert(m);
235
236 if ((u = m->userdata)) {
237
238 if (u->connection)
239 SmcCloseConnection(u->connection, 0, NULL);
240
241 if (u->client)
242 pa_client_free(u->client);
243
244 if (u->x11)
245 pa_x11_wrapper_unref(u->x11);
246
247 pa_xfree(u);
248 }
249
250 if (ice_in_use) {
251 IceRemoveConnectionWatch(new_ice_connection, m->core);
252 ice_in_use = FALSE;
253 }
254 }