]> code.delx.au - pulseaudio/blob - src/pulsecore/x11wrap.c
remaining s/assert/pa_assert/ and refcnt.h modernizations
[pulseaudio] / src / pulsecore / x11wrap.c
1 /* $Id$ */
2
3 /***
4 This file is part of PulseAudio.
5
6 Copyright 2004-2006 Lennart Poettering
7
8 PulseAudio is free software; you can redistribute it and/or modify
9 it under the terms of the GNU Lesser General Public License as published
10 by the Free Software Foundation; either version 2 of the License,
11 or (at your option) any later version.
12
13 PulseAudio is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with PulseAudio; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21 USA.
22 ***/
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <stdio.h>
29
30 #include <pulse/xmalloc.h>
31
32 #include <pulsecore/llist.h>
33 #include <pulsecore/log.h>
34 #include <pulsecore/props.h>
35 #include <pulsecore/core-util.h>
36 #include <pulsecore/macro.h>
37
38 #include "x11wrap.h"
39
40 typedef struct pa_x11_internal pa_x11_internal;
41
42 struct pa_x11_internal {
43 PA_LLIST_FIELDS(pa_x11_internal);
44 pa_x11_wrapper *wrapper;
45 pa_io_event* io_event;
46 int fd;
47 };
48
49 struct pa_x11_wrapper {
50 PA_REFCNT_DECLARE;
51 pa_core *core;
52
53 char *property_name;
54 Display *display;
55
56 pa_defer_event* defer_event;
57 pa_io_event* io_event;
58
59 PA_LLIST_HEAD(pa_x11_client, clients);
60 PA_LLIST_HEAD(pa_x11_internal, internals);
61 };
62
63 struct pa_x11_client {
64 PA_LLIST_FIELDS(pa_x11_client);
65 pa_x11_wrapper *wrapper;
66 int (*callback)(pa_x11_wrapper *w, XEvent *e, void *userdata);
67 void *userdata;
68 };
69
70 /* Dispatch all pending X11 events */
71 static void work(pa_x11_wrapper *w) {
72 pa_assert(w);
73 pa_assert(PA_REFCNT_VALUE(w) >= 1);
74
75 while (XPending(w->display)) {
76 pa_x11_client *c;
77 XEvent e;
78 XNextEvent(w->display, &e);
79
80 for (c = w->clients; c; c = c->next) {
81 pa_assert(c->callback);
82 if (c->callback(w, &e, c->userdata) != 0)
83 break;
84 }
85 }
86 }
87
88 /* IO notification event for the X11 display connection */
89 static void display_io_event(pa_mainloop_api *m, pa_io_event *e, int fd, PA_GCC_UNUSED pa_io_event_flags_t f, void *userdata) {
90 pa_x11_wrapper *w = userdata;
91
92 pa_assert(m);
93 pa_assert(e);
94 pa_assert(fd >= 0);
95 pa_assert(w);
96 pa_assert(PA_REFCNT_VALUE(w) >= 1);
97
98 work(w);
99 }
100
101 /* Deferred notification event. Called once each main loop iteration */
102 static void defer_event(pa_mainloop_api *m, pa_defer_event *e, void *userdata) {
103 pa_x11_wrapper *w = userdata;
104
105 pa_assert(m);
106 pa_assert(e);
107 pa_assert(w);
108 pa_assert(PA_REFCNT_VALUE(w) >= 1);
109
110 m->defer_enable(e, 0);
111
112 work(w);
113 }
114
115 /* IO notification event for X11 internal connections */
116 static void internal_io_event(pa_mainloop_api *m, pa_io_event *e, int fd, PA_GCC_UNUSED pa_io_event_flags_t f, void *userdata) {
117 pa_x11_wrapper *w = userdata;
118
119 pa_assert(m);
120 pa_assert(e);
121 pa_assert(fd >= 0);
122 pa_assert(w);
123 pa_assert(PA_REFCNT_VALUE(w) >= 1);
124
125 XProcessInternalConnection(w->display, fd);
126
127 work(w);
128 }
129
130 /* Add a new IO source for the specified X11 internal connection */
131 static pa_x11_internal* x11_internal_add(pa_x11_wrapper *w, int fd) {
132 pa_x11_internal *i;
133 pa_assert(fd >= 0);
134
135 i = pa_xnew(pa_x11_internal, 1);
136 i->wrapper = w;
137 i->io_event = w->core->mainloop->io_new(w->core->mainloop, fd, PA_IO_EVENT_INPUT, internal_io_event, w);
138 i->fd = fd;
139
140 PA_LLIST_PREPEND(pa_x11_internal, w->internals, i);
141 return i;
142 }
143
144 /* Remove an IO source for an X11 internal connection */
145 static void x11_internal_remove(pa_x11_wrapper *w, pa_x11_internal *i) {
146 pa_assert(i);
147
148 PA_LLIST_REMOVE(pa_x11_internal, w->internals, i);
149 w->core->mainloop->io_free(i->io_event);
150 pa_xfree(i);
151 }
152
153 /* Implementation of XConnectionWatchProc */
154 static void x11_watch(Display *display, XPointer userdata, int fd, Bool opening, XPointer *watch_data) {
155 pa_x11_wrapper *w = (pa_x11_wrapper*) userdata;
156
157 pa_assert(display);
158 pa_assert(w);
159 pa_assert(fd >= 0);
160
161 if (opening)
162 *watch_data = (XPointer) x11_internal_add(w, fd);
163 else
164 x11_internal_remove(w, (pa_x11_internal*) *watch_data);
165 }
166
167 static pa_x11_wrapper* x11_wrapper_new(pa_core *c, const char *name, const char *t) {
168 pa_x11_wrapper*w;
169 Display *d;
170
171 if (!(d = XOpenDisplay(name))) {
172 pa_log("XOpenDisplay() failed");
173 return NULL;
174 }
175
176 w = pa_xnew(pa_x11_wrapper, 1);
177 PA_REFCNT_INIT(w);
178 w->core = c;
179 w->property_name = pa_xstrdup(t);
180 w->display = d;
181
182 PA_LLIST_HEAD_INIT(pa_x11_client, w->clients);
183 PA_LLIST_HEAD_INIT(pa_x11_internal, w->internals);
184
185 w->defer_event = c->mainloop->defer_new(c->mainloop, defer_event, w);
186 w->io_event = c->mainloop->io_new(c->mainloop, ConnectionNumber(d), PA_IO_EVENT_INPUT, display_io_event, w);
187
188 XAddConnectionWatch(d, x11_watch, (XPointer) w);
189
190 pa_assert_se(pa_property_set(c, w->property_name, w) >= 0);
191
192 return w;
193 }
194
195 static void x11_wrapper_free(pa_x11_wrapper*w) {
196 pa_assert(w);
197
198 pa_assert_se(pa_property_remove(w->core, w->property_name) >= 0);
199
200 pa_assert(!w->clients);
201
202 XRemoveConnectionWatch(w->display, x11_watch, (XPointer) w);
203 XCloseDisplay(w->display);
204
205 w->core->mainloop->io_free(w->io_event);
206 w->core->mainloop->defer_free(w->defer_event);
207
208 while (w->internals)
209 x11_internal_remove(w, w->internals);
210
211 pa_xfree(w->property_name);
212 pa_xfree(w);
213 }
214
215 pa_x11_wrapper* pa_x11_wrapper_get(pa_core *c, const char *name) {
216 char t[256];
217 pa_x11_wrapper *w;
218
219 pa_core_assert_ref(c);
220
221 pa_snprintf(t, sizeof(t), "x11-wrapper%s%s", name ? "-" : "", name ? name : "");
222 if ((w = pa_property_get(c, t)))
223 return pa_x11_wrapper_ref(w);
224
225 return x11_wrapper_new(c, name, t);
226 }
227
228 pa_x11_wrapper* pa_x11_wrapper_ref(pa_x11_wrapper *w) {
229 pa_assert(w);
230 pa_assert(PA_REFCNT_VALUE(w) >= 1);
231
232 PA_REFCNT_INC(w);
233 return w;
234 }
235
236 void pa_x11_wrapper_unref(pa_x11_wrapper* w) {
237 pa_assert(w);
238 pa_assert(PA_REFCNT_VALUE(w) >= 1);
239
240 if (PA_REFCNT_DEC(w) <= 0)
241 x11_wrapper_free(w);
242 }
243
244 Display *pa_x11_wrapper_get_display(pa_x11_wrapper *w) {
245 pa_assert(w);
246 pa_assert(PA_REFCNT_VALUE(w) >= 1);
247
248 /* Somebody is using us, schedule a output buffer flush */
249 w->core->mainloop->defer_enable(w->defer_event, 1);
250
251 return w->display;
252 }
253
254 pa_x11_client* pa_x11_client_new(pa_x11_wrapper *w, int (*cb)(pa_x11_wrapper *w, XEvent *e, void *userdata), void *userdata) {
255 pa_x11_client *c;
256
257 pa_assert(w);
258 pa_assert(PA_REFCNT_VALUE(w) >= 1);
259
260 c = pa_xnew(pa_x11_client, 1);
261 c->wrapper = w;
262 c->callback = cb;
263 c->userdata = userdata;
264
265 PA_LLIST_PREPEND(pa_x11_client, w->clients, c);
266
267 return c;
268 }
269
270 void pa_x11_client_free(pa_x11_client *c) {
271 pa_assert(c);
272 pa_assert(c->wrapper);
273 pa_assert(PA_REFCNT_VALUE(c->wrapper) >= 1);
274
275 PA_LLIST_REMOVE(pa_x11_client, c->wrapper->clients, c);
276 pa_xfree(c);
277 }