2 This file is part of PulseAudio.
4 Copyright 2004-2006 Lennart Poettering
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.
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.
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
28 #include <pulse/xmalloc.h>
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>
38 typedef struct pa_x11_internal pa_x11_internal
;
40 struct pa_x11_internal
{
41 PA_LLIST_FIELDS(pa_x11_internal
);
42 pa_x11_wrapper
*wrapper
;
43 pa_io_event
* io_event
;
47 struct pa_x11_wrapper
{
54 pa_defer_event
* defer_event
;
55 pa_io_event
* io_event
;
57 PA_LLIST_HEAD(pa_x11_client
, clients
);
58 PA_LLIST_HEAD(pa_x11_internal
, internals
);
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
;
69 /* Dispatch all pending X11 events */
70 static void work(pa_x11_wrapper
*w
) {
72 pa_assert(PA_REFCNT_VALUE(w
) >= 1);
74 pa_x11_wrapper_ref(w
);
76 while (XPending(w
->display
)) {
79 XNextEvent(w
->display
, &e
);
81 for (c
= w
->clients
; c
; c
= n
) {
85 if (c
->event_cb(w
, &e
, c
->userdata
) != 0)
90 pa_x11_wrapper_unref(w
);
93 /* IO notification event for the X11 display connection */
94 static void display_io_event(pa_mainloop_api
*m
, pa_io_event
*e
, int fd
, pa_io_event_flags_t f
, void *userdata
) {
95 pa_x11_wrapper
*w
= userdata
;
101 pa_assert(PA_REFCNT_VALUE(w
) >= 1);
106 /* Deferred notification event. Called once each main loop iteration */
107 static void defer_event(pa_mainloop_api
*m
, pa_defer_event
*e
, void *userdata
) {
108 pa_x11_wrapper
*w
= userdata
;
113 pa_assert(PA_REFCNT_VALUE(w
) >= 1);
115 m
->defer_enable(e
, 0);
120 /* IO notification event for X11 internal connections */
121 static void internal_io_event(pa_mainloop_api
*m
, pa_io_event
*e
, int fd
, pa_io_event_flags_t f
, void *userdata
) {
122 pa_x11_wrapper
*w
= userdata
;
128 pa_assert(PA_REFCNT_VALUE(w
) >= 1);
130 XProcessInternalConnection(w
->display
, fd
);
135 /* Add a new IO source for the specified X11 internal connection */
136 static pa_x11_internal
* x11_internal_add(pa_x11_wrapper
*w
, int fd
) {
140 i
= pa_xnew(pa_x11_internal
, 1);
142 i
->io_event
= w
->core
->mainloop
->io_new(w
->core
->mainloop
, fd
, PA_IO_EVENT_INPUT
, internal_io_event
, w
);
145 PA_LLIST_PREPEND(pa_x11_internal
, w
->internals
, i
);
149 /* Remove an IO source for an X11 internal connection */
150 static void x11_internal_remove(pa_x11_wrapper
*w
, pa_x11_internal
*i
) {
153 PA_LLIST_REMOVE(pa_x11_internal
, w
->internals
, i
);
154 w
->core
->mainloop
->io_free(i
->io_event
);
158 /* Implementation of XConnectionWatchProc */
159 static void x11_watch(Display
*display
, XPointer userdata
, int fd
, Bool opening
, XPointer
*watch_data
) {
160 pa_x11_wrapper
*w
= (pa_x11_wrapper
*) userdata
;
167 *watch_data
= (XPointer
) x11_internal_add(w
, fd
);
169 x11_internal_remove(w
, (pa_x11_internal
*) *watch_data
);
172 static pa_x11_wrapper
* x11_wrapper_new(pa_core
*c
, const char *name
, const char *t
) {
176 if (!(d
= XOpenDisplay(name
))) {
177 pa_log("XOpenDisplay() failed");
181 w
= pa_xnew(pa_x11_wrapper
, 1);
184 w
->property_name
= pa_xstrdup(t
);
187 PA_LLIST_HEAD_INIT(pa_x11_client
, w
->clients
);
188 PA_LLIST_HEAD_INIT(pa_x11_internal
, w
->internals
);
190 w
->defer_event
= c
->mainloop
->defer_new(c
->mainloop
, defer_event
, w
);
191 w
->io_event
= c
->mainloop
->io_new(c
->mainloop
, ConnectionNumber(d
), PA_IO_EVENT_INPUT
, display_io_event
, w
);
193 XAddConnectionWatch(d
, x11_watch
, (XPointer
) w
);
195 pa_assert_se(pa_shared_set(c
, w
->property_name
, w
) >= 0);
200 static void x11_wrapper_free(pa_x11_wrapper
*w
) {
203 pa_assert_se(pa_shared_remove(w
->core
, w
->property_name
) >= 0);
205 pa_assert(!w
->clients
);
207 XRemoveConnectionWatch(w
->display
, x11_watch
, (XPointer
) w
);
208 XCloseDisplay(w
->display
);
210 w
->core
->mainloop
->io_free(w
->io_event
);
211 w
->core
->mainloop
->defer_free(w
->defer_event
);
214 x11_internal_remove(w
, w
->internals
);
216 pa_xfree(w
->property_name
);
220 pa_x11_wrapper
* pa_x11_wrapper_get(pa_core
*c
, const char *name
) {
224 pa_core_assert_ref(c
);
226 pa_snprintf(t
, sizeof(t
), "x11-wrapper%s%s", name
? "@" : "", name
? name
: "");
228 if ((w
= pa_shared_get(c
, t
)))
229 return pa_x11_wrapper_ref(w
);
231 return x11_wrapper_new(c
, name
, t
);
234 pa_x11_wrapper
* pa_x11_wrapper_ref(pa_x11_wrapper
*w
) {
236 pa_assert(PA_REFCNT_VALUE(w
) >= 1);
242 void pa_x11_wrapper_unref(pa_x11_wrapper
* w
) {
244 pa_assert(PA_REFCNT_VALUE(w
) >= 1);
246 if (PA_REFCNT_DEC(w
) > 0)
252 Display
*pa_x11_wrapper_get_display(pa_x11_wrapper
*w
) {
254 pa_assert(PA_REFCNT_VALUE(w
) >= 1);
256 /* Somebody is using us, schedule a output buffer flush */
257 w
->core
->mainloop
->defer_enable(w
->defer_event
, 1);
262 xcb_connection_t
*pa_x11_wrapper_get_xcb_connection(pa_x11_wrapper
*w
) {
263 return XGetXCBConnection(pa_x11_wrapper_get_display(w
));
266 void pa_x11_wrapper_kill(pa_x11_wrapper
*w
) {
267 pa_x11_client
*c
, *n
;
271 pa_x11_wrapper_ref(w
);
273 for (c
= w
->clients
; c
; c
= n
) {
277 c
->kill_cb(w
, c
->userdata
);
280 pa_x11_wrapper_unref(w
);
283 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
) {
287 pa_assert(PA_REFCNT_VALUE(w
) >= 1);
289 c
= pa_xnew(pa_x11_client
, 1);
291 c
->event_cb
= event_cb
;
292 c
->kill_cb
= kill_cb
;
293 c
->userdata
= userdata
;
295 PA_LLIST_PREPEND(pa_x11_client
, w
->clients
, c
);
300 void pa_x11_client_free(pa_x11_client
*c
) {
302 pa_assert(c
->wrapper
);
303 pa_assert(PA_REFCNT_VALUE(c
->wrapper
) >= 1);
305 PA_LLIST_REMOVE(pa_x11_client
, c
->wrapper
->clients
, c
);