]> code.delx.au - pulseaudio/blob - polyp/x11wrap.c
Make the whole stuff LGPL only
[pulseaudio] / polyp / x11wrap.c
1 /* $Id$ */
2
3 /***
4 This file is part of polypaudio.
5
6 polypaudio 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 polypaudio 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 polypaudio; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19 USA.
20 ***/
21
22 #include <assert.h>
23 #include <stdio.h>
24
25 #include "llist.h"
26 #include "x11wrap.h"
27 #include "xmalloc.h"
28 #include "log.h"
29 #include "props.h"
30
31 struct pa_x11_client;
32
33 struct pa_x11_internal {
34 PA_LLIST_FIELDS(struct pa_x11_internal);
35 struct pa_x11_wrapper *wrapper;
36 struct pa_io_event* io_event;
37 int fd;
38 };
39
40 struct pa_x11_wrapper {
41 struct pa_core *core;
42 int ref;
43
44 char *property_name;
45 Display *display;
46
47 struct pa_defer_event* defer_event;
48 struct pa_io_event* io_event;
49
50 PA_LLIST_HEAD(struct pa_x11_client, clients);
51 PA_LLIST_HEAD(struct pa_x11_internal, internals);
52 };
53
54 struct pa_x11_client {
55 PA_LLIST_FIELDS(struct pa_x11_client);
56 struct pa_x11_wrapper *wrapper;
57 int (*callback)(struct pa_x11_wrapper *w, XEvent *e, void *userdata);
58 void *userdata;
59 };
60
61 /* Dispatch all pending X11 events */
62 static void work(struct pa_x11_wrapper *w) {
63 assert(w && w->ref >= 1);
64
65 while (XPending(w->display)) {
66 struct pa_x11_client *c;
67 XEvent e;
68 XNextEvent(w->display, &e);
69
70 for (c = w->clients; c; c = c->next) {
71 assert(c->callback);
72 if (c->callback(w, &e, c->userdata) != 0)
73 break;
74 }
75 }
76 }
77
78 /* IO notification event for the X11 display connection */
79 static void display_io_event(struct pa_mainloop_api *m, struct pa_io_event *e, int fd, enum pa_io_event_flags f, void *userdata) {
80 struct pa_x11_wrapper *w = userdata;
81 assert(m && e && fd >= 0 && w && w->ref >= 1);
82 work(w);
83 }
84
85 /* Deferred notification event. Called once each main loop iteration */
86 static void defer_event(struct pa_mainloop_api *m, struct pa_defer_event *e, void *userdata) {
87 struct pa_x11_wrapper *w = userdata;
88 assert(m && e && w && w->ref >= 1);
89 work(w);
90 }
91
92 /* IO notification event for X11 internal connections */
93 static void internal_io_event(struct pa_mainloop_api *m, struct pa_io_event *e, int fd, enum pa_io_event_flags f, void *userdata) {
94 struct pa_x11_wrapper *w = userdata;
95 assert(m && e && fd >= 0 && w && w->ref >= 1);
96
97 XProcessInternalConnection(w->display, fd);
98 }
99
100 /* Add a new IO source for the specified X11 internal connection */
101 static struct pa_x11_internal* x11_internal_add(struct pa_x11_wrapper *w, int fd) {
102 struct pa_x11_internal *i;
103 assert(i && fd >= 0);
104
105 i = pa_xmalloc(sizeof(struct pa_x11_internal));
106 i->wrapper = w;
107 i->io_event = w->core->mainloop->io_new(w->core->mainloop, fd, PA_IO_EVENT_INPUT, internal_io_event, w);
108 i->fd = fd;
109
110 PA_LLIST_PREPEND(struct pa_x11_internal, w->internals, i);
111 return i;
112 }
113
114 /* Remove an IO source for an X11 internal connection */
115 void x11_internal_remove(struct pa_x11_wrapper *w, struct pa_x11_internal *i) {
116 assert(i);
117
118 PA_LLIST_REMOVE(struct pa_x11_internal, w->internals, i);
119 w->core->mainloop->io_free(i->io_event);
120 pa_xfree(i);
121 }
122
123 /* Implementation of XConnectionWatchProc */
124 static void x11_watch(Display *display, XPointer userdata, int fd, Bool opening, XPointer *watch_data) {
125 struct pa_x11_wrapper *w = (struct pa_x11_wrapper*) userdata;
126 assert(display && w && fd >= 0);
127
128 if (opening)
129 *watch_data = (XPointer) x11_internal_add(w, fd);
130 else
131 x11_internal_remove(w, (struct pa_x11_internal*) *watch_data);
132 }
133
134 static struct pa_x11_wrapper* x11_wrapper_new(struct pa_core *c, const char *name, const char *t) {
135 struct pa_x11_wrapper*w;
136 Display *d;
137 int r;
138
139 if (!(d = XOpenDisplay(name))) {
140 pa_log(__FILE__": XOpenDisplay() failed\n");
141 return NULL;
142 }
143
144 w = pa_xmalloc(sizeof(struct pa_x11_wrapper));
145 w->core = c;
146 w->ref = 1;
147 w->property_name = pa_xstrdup(t);
148 w->display = d;
149
150 PA_LLIST_HEAD_INIT(struct pa_x11_client, w->clients);
151 PA_LLIST_HEAD_INIT(struct pa_x11_internal, w->internals);
152
153 w->defer_event = c->mainloop->defer_new(c->mainloop, defer_event, w);
154 w->io_event = c->mainloop->io_new(c->mainloop, ConnectionNumber(d), PA_IO_EVENT_INPUT, display_io_event, w);
155
156 XAddConnectionWatch(d, x11_watch, (XPointer) w);
157
158 r = pa_property_set(c, w->property_name, w);
159 assert(r >= 0);
160
161 return w;
162 }
163
164 static void x11_wrapper_free(struct pa_x11_wrapper*w) {
165 int r;
166 assert(w);
167
168 r = pa_property_remove(w->core, w->property_name);
169 assert(r >= 0);
170
171 assert(!w->clients);
172
173 XRemoveConnectionWatch(w->display, x11_watch, (XPointer) w);
174 XCloseDisplay(w->display);
175
176 w->core->mainloop->io_free(w->io_event);
177 w->core->mainloop->defer_free(w->defer_event);
178
179 while (w->internals)
180 x11_internal_remove(w, w->internals);
181
182 pa_xfree(w->property_name);
183 pa_xfree(w);
184 }
185
186 struct pa_x11_wrapper* pa_x11_wrapper_get(struct pa_core *c, const char *name) {
187 char t[256];
188 struct pa_x11_wrapper *w;
189 assert(c);
190
191 snprintf(t, sizeof(t), "x11-wrapper%s%s", name ? "-" : "", name ? name : "");
192 if ((w = pa_property_get(c, t)))
193 return pa_x11_wrapper_ref(w);
194
195 return x11_wrapper_new(c, name, t);
196 }
197
198 struct pa_x11_wrapper* pa_x11_wrapper_ref(struct pa_x11_wrapper *w) {
199 assert(w && w->ref >= 1);
200 w->ref++;
201 return w;
202 }
203
204 void pa_x11_wrapper_unref(struct pa_x11_wrapper* w) {
205 assert(w && w->ref >= 1);
206
207 if (!(--w->ref))
208 x11_wrapper_free(w);
209 }
210
211 Display *pa_x11_wrapper_get_display(struct pa_x11_wrapper *w) {
212 assert(w && w->ref >= 1);
213 return w->display;
214 }
215
216 struct pa_x11_client* pa_x11_client_new(struct pa_x11_wrapper *w, int (*cb)(struct pa_x11_wrapper *w, XEvent *e, void *userdata), void *userdata) {
217 struct pa_x11_client *c;
218 assert(w && w->ref >= 1);
219
220 c = pa_xmalloc(sizeof(struct pa_x11_client));
221 c->wrapper = w;
222 c->callback = cb;
223 c->userdata = userdata;
224
225 PA_LLIST_PREPEND(struct pa_x11_client, w->clients, c);
226
227 return c;
228 }
229
230 void pa_x11_client_free(struct pa_x11_client *c) {
231 assert(c && c->wrapper && c->wrapper->ref >= 1);
232
233 PA_LLIST_REMOVE(struct pa_x11_client, c->wrapper->clients, c);
234 pa_xfree(c);
235 }