4 This file is part of PulseAudio.
6 Copyright 2004-2006 Lennart Poettering
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.
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.
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
27 #include <pulse/xmalloc.h>
29 #include <pulsecore/llist.h>
30 #include <pulsecore/log.h>
31 #include <pulsecore/props.h>
32 #include <pulsecore/core-util.h>
36 typedef struct pa_x11_internal pa_x11_internal
;
38 struct pa_x11_internal
{
39 PA_LLIST_FIELDS(pa_x11_internal
);
40 pa_x11_wrapper
*wrapper
;
41 pa_io_event
* io_event
;
45 struct pa_x11_wrapper
{
52 pa_defer_event
* defer_event
;
53 pa_io_event
* io_event
;
55 PA_LLIST_HEAD(pa_x11_client
, clients
);
56 PA_LLIST_HEAD(pa_x11_internal
, internals
);
59 struct pa_x11_client
{
60 PA_LLIST_FIELDS(pa_x11_client
);
61 pa_x11_wrapper
*wrapper
;
62 int (*callback
)(pa_x11_wrapper
*w
, XEvent
*e
, void *userdata
);
66 /* Dispatch all pending X11 events */
67 static void work(pa_x11_wrapper
*w
) {
68 assert(w
&& w
->ref
>= 1);
70 while (XPending(w
->display
)) {
73 XNextEvent(w
->display
, &e
);
75 for (c
= w
->clients
; c
; c
= c
->next
) {
77 if (c
->callback(w
, &e
, c
->userdata
) != 0)
83 /* IO notification event for the X11 display connection */
84 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
) {
85 pa_x11_wrapper
*w
= userdata
;
86 assert(m
&& e
&& fd
>= 0 && w
&& w
->ref
>= 1);
90 /* Deferred notification event. Called once each main loop iteration */
91 static void defer_event(pa_mainloop_api
*m
, pa_defer_event
*e
, void *userdata
) {
92 pa_x11_wrapper
*w
= userdata
;
93 assert(m
&& e
&& w
&& w
->ref
>= 1);
95 m
->defer_enable(e
, 0);
100 /* IO notification event for X11 internal connections */
101 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
) {
102 pa_x11_wrapper
*w
= userdata
;
103 assert(m
&& e
&& fd
>= 0 && w
&& w
->ref
>= 1);
105 XProcessInternalConnection(w
->display
, fd
);
110 /* Add a new IO source for the specified X11 internal connection */
111 static pa_x11_internal
* x11_internal_add(pa_x11_wrapper
*w
, int fd
) {
115 i
= pa_xmalloc(sizeof(pa_x11_internal
));
118 i
->io_event
= w
->core
->mainloop
->io_new(w
->core
->mainloop
, fd
, PA_IO_EVENT_INPUT
, internal_io_event
, w
);
121 PA_LLIST_PREPEND(pa_x11_internal
, w
->internals
, i
);
125 /* Remove an IO source for an X11 internal connection */
126 static void x11_internal_remove(pa_x11_wrapper
*w
, pa_x11_internal
*i
) {
129 PA_LLIST_REMOVE(pa_x11_internal
, w
->internals
, i
);
130 w
->core
->mainloop
->io_free(i
->io_event
);
134 /* Implementation of XConnectionWatchProc */
135 static void x11_watch(Display
*display
, XPointer userdata
, int fd
, Bool opening
, XPointer
*watch_data
) {
136 pa_x11_wrapper
*w
= (pa_x11_wrapper
*) userdata
;
137 assert(display
&& w
&& fd
>= 0);
140 *watch_data
= (XPointer
) x11_internal_add(w
, fd
);
142 x11_internal_remove(w
, (pa_x11_internal
*) *watch_data
);
145 static pa_x11_wrapper
* x11_wrapper_new(pa_core
*c
, const char *name
, const char *t
) {
150 if (!(d
= XOpenDisplay(name
))) {
151 pa_log("XOpenDisplay() failed");
155 w
= pa_xmalloc(sizeof(pa_x11_wrapper
));
158 w
->property_name
= pa_xstrdup(t
);
161 PA_LLIST_HEAD_INIT(pa_x11_client
, w
->clients
);
162 PA_LLIST_HEAD_INIT(pa_x11_internal
, w
->internals
);
164 w
->defer_event
= c
->mainloop
->defer_new(c
->mainloop
, defer_event
, w
);
165 w
->io_event
= c
->mainloop
->io_new(c
->mainloop
, ConnectionNumber(d
), PA_IO_EVENT_INPUT
, display_io_event
, w
);
167 XAddConnectionWatch(d
, x11_watch
, (XPointer
) w
);
169 r
= pa_property_set(c
, w
->property_name
, w
);
175 static void x11_wrapper_free(pa_x11_wrapper
*w
) {
179 r
= pa_property_remove(w
->core
, w
->property_name
);
184 XRemoveConnectionWatch(w
->display
, x11_watch
, (XPointer
) w
);
185 XCloseDisplay(w
->display
);
187 w
->core
->mainloop
->io_free(w
->io_event
);
188 w
->core
->mainloop
->defer_free(w
->defer_event
);
191 x11_internal_remove(w
, w
->internals
);
193 pa_xfree(w
->property_name
);
197 pa_x11_wrapper
* pa_x11_wrapper_get(pa_core
*c
, const char *name
) {
202 pa_snprintf(t
, sizeof(t
), "x11-wrapper%s%s", name
? "-" : "", name
? name
: "");
203 if ((w
= pa_property_get(c
, t
)))
204 return pa_x11_wrapper_ref(w
);
206 return x11_wrapper_new(c
, name
, t
);
209 pa_x11_wrapper
* pa_x11_wrapper_ref(pa_x11_wrapper
*w
) {
210 assert(w
&& w
->ref
>= 1);
215 void pa_x11_wrapper_unref(pa_x11_wrapper
* w
) {
216 assert(w
&& w
->ref
>= 1);
222 Display
*pa_x11_wrapper_get_display(pa_x11_wrapper
*w
) {
223 assert(w
&& w
->ref
>= 1);
225 /* Somebody is using us, schedule a output buffer flush */
226 w
->core
->mainloop
->defer_enable(w
->defer_event
, 1);
231 pa_x11_client
* pa_x11_client_new(pa_x11_wrapper
*w
, int (*cb
)(pa_x11_wrapper
*w
, XEvent
*e
, void *userdata
), void *userdata
) {
233 assert(w
&& w
->ref
>= 1);
235 c
= pa_xmalloc(sizeof(pa_x11_client
));
238 c
->userdata
= userdata
;
240 PA_LLIST_PREPEND(pa_x11_client
, w
->clients
, c
);
245 void pa_x11_client_free(pa_x11_client
*c
) {
246 assert(c
&& c
->wrapper
&& c
->wrapper
->ref
>= 1);
248 PA_LLIST_REMOVE(pa_x11_client
, c
->wrapper
->clients
, c
);