Branch data Line data Source code
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 : :
28 : : #include <pulse/xmalloc.h>
29 : :
30 : : #include <pulsecore/llist.h>
31 : : #include <pulsecore/log.h>
32 : : #include <pulsecore/shared.h>
33 : : #include <pulsecore/core-util.h>
34 : : #include <pulsecore/macro.h>
35 : :
36 : : #include "x11wrap.h"
37 : :
38 : : typedef struct pa_x11_internal pa_x11_internal;
39 : :
40 : : struct pa_x11_internal {
41 : : PA_LLIST_FIELDS(pa_x11_internal);
42 : : pa_x11_wrapper *wrapper;
43 : : pa_io_event* io_event;
44 : : int fd;
45 : : };
46 : :
47 : : struct pa_x11_wrapper {
48 : : PA_REFCNT_DECLARE;
49 : : pa_core *core;
50 : :
51 : : char *property_name;
52 : : Display *display;
53 : :
54 : : pa_defer_event* defer_event;
55 : : pa_io_event* io_event;
56 : :
57 : : PA_LLIST_HEAD(pa_x11_client, clients);
58 : : PA_LLIST_HEAD(pa_x11_internal, internals);
59 : : };
60 : :
61 : : struct pa_x11_client {
62 : : PA_LLIST_FIELDS(pa_x11_client);
63 : : pa_x11_wrapper *wrapper;
64 : : pa_x11_event_cb_t event_cb;
65 : : pa_x11_kill_cb_t kill_cb;
66 : : void *userdata;
67 : : };
68 : :
69 : : /* Dispatch all pending X11 events */
70 : 0 : static void work(pa_x11_wrapper *w) {
71 [ # # ]: 0 : pa_assert(w);
72 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(w) >= 1);
73 : :
74 : 0 : pa_x11_wrapper_ref(w);
75 : :
76 [ # # ]: 0 : while (XPending(w->display)) {
77 : : pa_x11_client *c, *n;
78 : : XEvent e;
79 : 0 : XNextEvent(w->display, &e);
80 : :
81 [ # # ]: 0 : for (c = w->clients; c; c = n) {
82 : 0 : n = c->next;
83 : :
84 [ # # ]: 0 : if (c->event_cb)
85 [ # # ]: 0 : if (c->event_cb(w, &e, c->userdata) != 0)
86 : : break;
87 : : }
88 : : }
89 : :
90 : 0 : pa_x11_wrapper_unref(w);
91 : 0 : }
92 : :
93 : : /* IO notification event for the X11 display connection */
94 : 0 : static void display_io_event(pa_mainloop_api *m, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) {
95 : 0 : pa_x11_wrapper *w = userdata;
96 : :
97 [ # # ]: 0 : pa_assert(m);
98 [ # # ]: 0 : pa_assert(e);
99 [ # # ]: 0 : pa_assert(fd >= 0);
100 [ # # ]: 0 : pa_assert(w);
101 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(w) >= 1);
102 : :
103 : 0 : work(w);
104 : 0 : }
105 : :
106 : : /* Deferred notification event. Called once each main loop iteration */
107 : 0 : static void defer_event(pa_mainloop_api *m, pa_defer_event *e, void *userdata) {
108 : 0 : pa_x11_wrapper *w = userdata;
109 : :
110 [ # # ]: 0 : pa_assert(m);
111 [ # # ]: 0 : pa_assert(e);
112 [ # # ]: 0 : pa_assert(w);
113 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(w) >= 1);
114 : :
115 : 0 : m->defer_enable(e, 0);
116 : :
117 : 0 : work(w);
118 : 0 : }
119 : :
120 : : /* IO notification event for X11 internal connections */
121 : 0 : static void internal_io_event(pa_mainloop_api *m, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) {
122 : 0 : pa_x11_wrapper *w = userdata;
123 : :
124 [ # # ]: 0 : pa_assert(m);
125 [ # # ]: 0 : pa_assert(e);
126 [ # # ]: 0 : pa_assert(fd >= 0);
127 [ # # ]: 0 : pa_assert(w);
128 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(w) >= 1);
129 : :
130 : 0 : XProcessInternalConnection(w->display, fd);
131 : :
132 : 0 : work(w);
133 : 0 : }
134 : :
135 : : /* Add a new IO source for the specified X11 internal connection */
136 : 0 : static pa_x11_internal* x11_internal_add(pa_x11_wrapper *w, int fd) {
137 : : pa_x11_internal *i;
138 [ # # ]: 0 : pa_assert(fd >= 0);
139 : :
140 : 0 : i = pa_xnew(pa_x11_internal, 1);
141 : 0 : i->wrapper = w;
142 : 0 : i->io_event = w->core->mainloop->io_new(w->core->mainloop, fd, PA_IO_EVENT_INPUT, internal_io_event, w);
143 : 0 : i->fd = fd;
144 : :
145 [ # # ][ # # ]: 0 : PA_LLIST_PREPEND(pa_x11_internal, w->internals, i);
146 : 0 : return i;
147 : : }
148 : :
149 : : /* Remove an IO source for an X11 internal connection */
150 : 0 : static void x11_internal_remove(pa_x11_wrapper *w, pa_x11_internal *i) {
151 [ # # ]: 0 : pa_assert(i);
152 : :
153 [ # # ][ # # ]: 0 : PA_LLIST_REMOVE(pa_x11_internal, w->internals, i);
[ # # ][ # # ]
154 : 0 : w->core->mainloop->io_free(i->io_event);
155 : 0 : pa_xfree(i);
156 : 0 : }
157 : :
158 : : /* Implementation of XConnectionWatchProc */
159 : 0 : static void x11_watch(Display *display, XPointer userdata, int fd, Bool opening, XPointer *watch_data) {
160 : 0 : pa_x11_wrapper *w = (pa_x11_wrapper*) userdata;
161 : :
162 [ # # ]: 0 : pa_assert(display);
163 [ # # ]: 0 : pa_assert(w);
164 [ # # ]: 0 : pa_assert(fd >= 0);
165 : :
166 [ # # ]: 0 : if (opening)
167 : 0 : *watch_data = (XPointer) x11_internal_add(w, fd);
168 : : else
169 : 0 : x11_internal_remove(w, (pa_x11_internal*) *watch_data);
170 : 0 : }
171 : :
172 : 0 : static pa_x11_wrapper* x11_wrapper_new(pa_core *c, const char *name, const char *t) {
173 : : pa_x11_wrapper*w;
174 : : Display *d;
175 : :
176 [ # # ]: 0 : if (!(d = XOpenDisplay(name))) {
177 : 0 : pa_log("XOpenDisplay() failed");
178 : 0 : return NULL;
179 : : }
180 : :
181 : 0 : w = pa_xnew(pa_x11_wrapper, 1);
182 : 0 : PA_REFCNT_INIT(w);
183 : 0 : w->core = c;
184 : 0 : w->property_name = pa_xstrdup(t);
185 : 0 : w->display = d;
186 : :
187 : 0 : PA_LLIST_HEAD_INIT(pa_x11_client, w->clients);
188 : 0 : PA_LLIST_HEAD_INIT(pa_x11_internal, w->internals);
189 : :
190 : 0 : w->defer_event = c->mainloop->defer_new(c->mainloop, defer_event, w);
191 : 0 : w->io_event = c->mainloop->io_new(c->mainloop, ConnectionNumber(d), PA_IO_EVENT_INPUT, display_io_event, w);
192 : :
193 : 0 : XAddConnectionWatch(d, x11_watch, (XPointer) w);
194 : :
195 [ # # ]: 0 : pa_assert_se(pa_shared_set(c, w->property_name, w) >= 0);
196 : :
197 : : return w;
198 : : }
199 : :
200 : 0 : static void x11_wrapper_free(pa_x11_wrapper*w) {
201 [ # # ]: 0 : pa_assert(w);
202 : :
203 [ # # ]: 0 : pa_assert_se(pa_shared_remove(w->core, w->property_name) >= 0);
204 : :
205 [ # # ]: 0 : pa_assert(!w->clients);
206 : :
207 : 0 : XRemoveConnectionWatch(w->display, x11_watch, (XPointer) w);
208 : 0 : XCloseDisplay(w->display);
209 : :
210 : 0 : w->core->mainloop->io_free(w->io_event);
211 : 0 : w->core->mainloop->defer_free(w->defer_event);
212 : :
213 [ # # ]: 0 : while (w->internals)
214 : 0 : x11_internal_remove(w, w->internals);
215 : :
216 : 0 : pa_xfree(w->property_name);
217 : 0 : pa_xfree(w);
218 : 0 : }
219 : :
220 : 0 : pa_x11_wrapper* pa_x11_wrapper_get(pa_core *c, const char *name) {
221 : : char t[256];
222 : : pa_x11_wrapper *w;
223 : :
224 : : pa_core_assert_ref(c);
225 : :
226 [ # # ][ # # ]: 0 : pa_snprintf(t, sizeof(t), "x11-wrapper%s%s", name ? "@" : "", name ? name : "");
227 : :
228 [ # # ]: 0 : if ((w = pa_shared_get(c, t)))
229 : 0 : return pa_x11_wrapper_ref(w);
230 : :
231 : 0 : return x11_wrapper_new(c, name, t);
232 : : }
233 : :
234 : 0 : pa_x11_wrapper* pa_x11_wrapper_ref(pa_x11_wrapper *w) {
235 [ # # ]: 0 : pa_assert(w);
236 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(w) >= 1);
237 : :
238 : 0 : PA_REFCNT_INC(w);
239 : 0 : return w;
240 : : }
241 : :
242 : 0 : void pa_x11_wrapper_unref(pa_x11_wrapper* w) {
243 [ # # ]: 0 : pa_assert(w);
244 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(w) >= 1);
245 : :
246 [ # # ]: 0 : if (PA_REFCNT_DEC(w) > 0)
247 : 0 : return;
248 : :
249 : 0 : x11_wrapper_free(w);
250 : : }
251 : :
252 : 0 : Display *pa_x11_wrapper_get_display(pa_x11_wrapper *w) {
253 [ # # ]: 0 : pa_assert(w);
254 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(w) >= 1);
255 : :
256 : : /* Somebody is using us, schedule a output buffer flush */
257 : 0 : w->core->mainloop->defer_enable(w->defer_event, 1);
258 : :
259 : 0 : return w->display;
260 : : }
261 : :
262 : 0 : xcb_connection_t *pa_x11_wrapper_get_xcb_connection(pa_x11_wrapper *w) {
263 : 0 : return XGetXCBConnection(pa_x11_wrapper_get_display(w));
264 : : }
265 : :
266 : 0 : void pa_x11_wrapper_kill(pa_x11_wrapper *w) {
267 : : pa_x11_client *c, *n;
268 : :
269 [ # # ]: 0 : pa_assert(w);
270 : :
271 : 0 : pa_x11_wrapper_ref(w);
272 : :
273 [ # # ]: 0 : for (c = w->clients; c; c = n) {
274 : 0 : n = c->next;
275 : :
276 [ # # ]: 0 : if (c->kill_cb)
277 : 0 : c->kill_cb(w, c->userdata);
278 : : }
279 : :
280 : 0 : pa_x11_wrapper_unref(w);
281 : 0 : }
282 : :
283 : 0 : pa_x11_client* pa_x11_client_new(pa_x11_wrapper *w, pa_x11_event_cb_t event_cb, pa_x11_kill_cb_t kill_cb, void *userdata) {
284 : : pa_x11_client *c;
285 : :
286 [ # # ]: 0 : pa_assert(w);
287 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(w) >= 1);
288 : :
289 : 0 : c = pa_xnew(pa_x11_client, 1);
290 : 0 : c->wrapper = w;
291 : 0 : c->event_cb = event_cb;
292 : 0 : c->kill_cb = kill_cb;
293 : 0 : c->userdata = userdata;
294 : :
295 [ # # ][ # # ]: 0 : PA_LLIST_PREPEND(pa_x11_client, w->clients, c);
296 : :
297 : 0 : return c;
298 : : }
299 : :
300 : 0 : void pa_x11_client_free(pa_x11_client *c) {
301 [ # # ]: 0 : pa_assert(c);
302 [ # # ]: 0 : pa_assert(c->wrapper);
303 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(c->wrapper) >= 1);
304 : :
305 [ # # ][ # # ]: 0 : PA_LLIST_REMOVE(pa_x11_client, c->wrapper->clients, c);
[ # # ][ # # ]
306 : 0 : pa_xfree(c);
307 : 0 : }
|