12e100b7d91930441a0f93908db9950002c0d0d1
[profile/ivi/pulseaudio-panda.git] / src / modules / 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 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, *k;
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
128     pa_assert(m);
129
130     if (ice_in_use) {
131         pa_log("module-x11-xsmp may no be loaded twice.");
132         return -1;
133     }
134
135     IceAddConnectionWatch(new_ice_connection, m->core);
136     ice_in_use = TRUE;
137
138     m->userdata = u = pa_xnew(struct userdata, 1);
139     u->core = m->core;
140     u->module = m;
141     u->client = NULL;
142     u->connection = NULL;
143     u->x11 = NULL;
144
145     if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
146         pa_log("Failed to parse module arguments");
147         goto fail;
148     }
149
150     if (!(u->x11 = pa_x11_wrapper_get(m->core, pa_modargs_get_value(ma, "display", NULL))))
151         goto fail;
152
153     e = pa_modargs_get_value(ma, "session_manager", NULL);
154
155     if (!e && !getenv("SESSION_MANAGER")) {
156         pa_log("X11 session manager not running.");
157         goto fail;
158     }
159
160     memset(&callbacks, 0, sizeof(callbacks));
161     callbacks.die.callback = die_cb;
162     callbacks.die.client_data = u;
163     callbacks.save_yourself.callback = save_yourself_cb;
164     callbacks.save_yourself.client_data = m->core;
165     callbacks.save_complete.callback = save_complete_cb;
166     callbacks.save_complete.client_data = m->core;
167     callbacks.shutdown_cancelled.callback = shutdown_cancelled_cb;
168     callbacks.shutdown_cancelled.client_data = m->core;
169
170     if (!(u->connection = SmcOpenConnection(
171                   (char*) e, m->core,
172                   SmProtoMajor, SmProtoMinor,
173                   SmcSaveYourselfProcMask | SmcDieProcMask | SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask,
174                   &callbacks, NULL, &client_id,
175                   sizeof(t), t))) {
176
177         pa_log("Failed to open connection to session manager: %s", t);
178         goto fail;
179     }
180
181     prop_program.name = (char*) SmProgram;
182     prop_program.type = (char*) SmARRAY8;
183     val_program.value = (char*) PACKAGE_NAME;
184     val_program.length = strlen(val_program.value);
185     prop_program.num_vals = 1;
186     prop_program.vals = &val_program;
187     prop_list[0] = &prop_program;
188
189     prop_user.name = (char*) SmUserID;
190     prop_user.type = (char*) SmARRAY8;
191     pa_get_user_name(t, sizeof(t));
192     val_user.value = t;
193     val_user.length = strlen(val_user.value);
194     prop_user.num_vals = 1;
195     prop_user.vals = &val_user;
196     prop_list[1] = &prop_user;
197
198     SmcSetProperties(u->connection, PA_ELEMENTSOF(prop_list), prop_list);
199
200     pa_log_info("Connected to session manager '%s' as '%s'.", vendor = SmcVendor(u->connection), client_id);
201     k = pa_sprintf_malloc("XSMP Session on %s as %s", vendor, client_id);
202     u->client = pa_client_new(u->core, __FILE__, k);
203     pa_xfree(k);
204
205     pa_proplist_sets(u->client->proplist, "xsmp.vendor", vendor);
206     pa_proplist_sets(u->client->proplist, "xsmp.client.id", client_id);
207
208     free(vendor);
209     free(client_id);
210
211     pa_modargs_free(ma);
212
213     return 0;
214
215 fail:
216     if (ma)
217         pa_modargs_free(ma);
218
219     pa__done(m);
220
221     return -1;
222 }
223
224 void pa__done(pa_module*m) {
225     struct userdata *u;
226
227     pa_assert(m);
228
229     if ((u = m->userdata)) {
230
231         if (u->connection)
232             SmcCloseConnection(u->connection, 0, NULL);
233
234         if (u->client)
235             pa_client_free(u->client);
236
237         if (u->x11)
238             pa_x11_wrapper_unref(u->x11);
239
240         pa_xfree(u);
241     }
242
243     if (ice_in_use) {
244         IceRemoveConnectionWatch(new_ice_connection, m->core);
245         ice_in_use = FALSE;
246     }
247 }