Merging upstream version 0.5.3 (Closes: #805659 CVE-2015-8308).
[debian/lxdm.git] / src / xconn.c
CommitLineData
9931e273
DB
1#include <unistd.h>
2#include <string.h>
3#include <stdlib.h>
4#include <stdio.h>
5#include <glib.h>
6
7#ifdef LXDM_XCONN_XLIB
8#include <X11/Xlib.h>
9#include <X11/XKBlib.h>
10#include <setjmp.h>
11#endif
12
13#ifdef LXDM_XCONN_XCB
14#include <xcb/xcb.h>
15#include <xcb/xproto.h>
16#endif
17
18#ifdef LXDM_XCONN_XLIB
19
20typedef Display *xconn_t;
21
22static int CatchErrors(Display *dpy, XErrorEvent *ev)
23{
24 return 0;
25}
26
27static jmp_buf XErrEnv;
28static int CatchIOErrors(Display *dpy)
29{
30 close(ConnectionNumber(dpy));
31 longjmp(XErrEnv,1);
32 return 0;
33}
34
35xconn_t xconn_open(const char *display)
36{
37 return XOpenDisplay(display);
38}
39
40void xconn_close(xconn_t c)
41{
42 if(!c) return;
43 XSetErrorHandler(CatchErrors);
44 XSetIOErrorHandler(CatchIOErrors);
45 if(!setjmp(XErrEnv))
46 XCloseDisplay(c);
47 XSetErrorHandler(NULL);
48 XSetIOErrorHandler(NULL);
49}
50
51void xconn_clean(xconn_t c)
52{
53 Window dummy, parent;
54 Window *children;
55 unsigned int nchildren;
56 unsigned int i;
57 Window Root;
d6ba7c28 58
9931e273 59 if(!c) return;
d6ba7c28 60
9931e273
DB
61 XSetErrorHandler(CatchErrors);
62 XSetIOErrorHandler(CatchIOErrors);
63
64 Root = DefaultRootWindow(c);
65
66 nchildren = 0;
67 if(!setjmp(XErrEnv))
68 XQueryTree(c, Root, &dummy, &parent, &children, &nchildren);
69 else
70 goto out;
71 for( i = 0; i < nchildren; i++ )
72 {
73 if(!setjmp(XErrEnv))
74 XKillClient(c, children[i]);
75 }
76 XFree((char *)children);
77 if(!setjmp(XErrEnv))
78 XSync(c, 0);
79out:
80 XSetErrorHandler(NULL);
81 XSetIOErrorHandler(NULL);
82}
83
84#endif
85
86#ifdef LXDM_XCONN_XCB
87
88typedef struct{
89 guint id;
90 xcb_connection_t *c;
91}*xconn_t;
92
93typedef struct _XConnSource
94{
95 GSource source;
96 GPollFD poll;
97}XConnSource;
98
99typedef gboolean (*XConnFunc)(gpointer data,xcb_generic_event_t *event);
100
101static gboolean xconn_prepare (GSource *source,gint *timeout)
102{
103 *timeout=-1;
104 return FALSE;
105}
106
107static gboolean xconn_check(GSource *source)
108{
109 XConnSource *s=(XConnSource*)source;
110 if((s->poll.revents & G_IO_IN))
111 return TRUE;
112 return FALSE;
113}
114
115static gboolean xconn_dispatch (GSource *source,GSourceFunc callback,gpointer user_data)
116{
117 xconn_t c=user_data;
118 xcb_generic_event_t *event;
119 while((event=xcb_poll_for_event(c->c))!=NULL)
120 {
121 ((XConnFunc)callback)(user_data,event);
122 free(event);
123 }
124 return TRUE;
125}
126
127static GSourceFuncs xconn_funcs =
128{
129 xconn_prepare,
130 xconn_check,
131 xconn_dispatch,
132 NULL
133};
134
135static gboolean xconn_func(gpointer data,xcb_generic_event_t *event)
136{
137 return TRUE;
138}
139
140
141xconn_t xconn_open(const char *display)
142{
143 XConnSource *s;
144 xcb_connection_t *dpy;
145 xconn_t c;
146 int fd;
147 dpy=xcb_connect(display,0);
148 /* is error in setup stage, there is memory leak at xcb */
149 if(!dpy || xcb_connection_has_error(dpy))
150 return NULL;
151 c=malloc(sizeof(*c));
152 c->c=dpy;
153 fd=xcb_get_file_descriptor(dpy);
154 s=(XConnSource*)g_source_new(&xconn_funcs,sizeof(XConnSource));
155 g_source_set_callback((GSource*)s,(GSourceFunc)xconn_func,c,NULL);
156
157 s->poll.fd=fd;
158 s->poll.events=G_IO_IN;
159 g_source_add_poll((GSource*)s,&s->poll);
160 c->id=g_source_attach((GSource*)s,NULL);
161 return c;
162}
163
164void xconn_close(xconn_t c)
165{
166 if(!c) return;
167 g_source_remove(c->id);
168 /* hack, clear the xcb has_error, so we can free it any way */
169 if(xcb_connection_has_error(c->c) && *(int*)c->c==1)
170 *(int*)c->c=0;
171 xcb_disconnect(c->c);
172 free(c);
173}
174
37f5420c 175#if 1
9931e273
DB
176static xcb_window_t xconn_get_root(xconn_t c)
177{
178 const xcb_setup_t *setup;
179 setup=xcb_get_setup(c->c);
180 xcb_screen_iterator_t iter = xcb_setup_roots_iterator (setup);
181 xcb_screen_t *screen = iter.data;
182 return screen->root;
183}
37f5420c
AG
184
185static char *xconn_atom_name(xcb_connection_t *c,xcb_atom_t atom)
186{
187 xcb_get_atom_name_cookie_t cookie;
188 xcb_get_atom_name_reply_t *reply;
189 char *buf;
190 int len;
191 char *res=NULL;
192 cookie=xcb_get_atom_name(c,atom);
193 reply=xcb_get_atom_name_reply(c,cookie,NULL);
194 if(!reply)
195 return NULL;
196 buf=xcb_get_atom_name_name(reply);
197 len=xcb_get_atom_name_name_length(reply);
198 if(buf && len>0)
199 {
200 res=malloc(len+1);
201 memcpy(res,buf,len);
202 res[len]=0;
203 }
204 free(reply);
205 return res;
206}
207
208static void xconn_clear_props(xcb_connection_t *c,xcb_window_t w)
209{
210 xcb_list_properties_cookie_t cookie;
211 xcb_list_properties_reply_t *reply;
212 xcb_atom_t *atoms;
213 int i,len;
214 xcb_atom_t temp[16];
215 int temp_len=0;
216 cookie=xcb_list_properties(c,w);
217 reply=xcb_list_properties_reply(c,cookie,NULL);
218 if(!reply)
219 return;
220 len=xcb_list_properties_atoms_length(reply);
221 atoms=xcb_list_properties_atoms(reply);
222 for(i=0;i<len;i++)
223 {
224 int prop=atoms[i];
225 //if(prop<=68)
226 // continue;
227 char *name=xconn_atom_name(c,prop);
228 if(!name)
229 break;
230 if(!strcmp(name,"PULSE_SERVER") ||
231 !strcmp(name,"PULSE_COOKIE"))
232 {
233 temp[temp_len++]=prop;
234 }
235 free(name);
236 }
237 free(reply);
238 for(i=0;i<temp_len;i++)
239 {
240 xcb_delete_property_checked(c,w,temp[i]);
241 }
242}
243
9931e273
DB
244#endif
245
246void xconn_clean(xconn_t c)
247{
37f5420c 248#if 1
9931e273
DB
249 xcb_query_tree_cookie_t wintree;
250 xcb_query_tree_reply_t *rep;
251 xcb_window_t *children;
252 xcb_window_t root;
253 int i,len;
254 if(!c) return;
255 root=xconn_get_root(c);
256 wintree = xcb_query_tree(c->c, root);
257 rep = xcb_query_tree_reply(c->c, wintree, 0);
258 if(!rep) return;
259 len = xcb_query_tree_children_length(rep);
260 children = xcb_query_tree_children(rep);
261 for(i=0;i<len;i++)
262 xcb_kill_client(c->c,children[i]);
263 free(rep);
37f5420c 264 xconn_clear_props(c->c,root);
9931e273
DB
265 xcb_flush(c->c);
266#endif
267}
268
269#endif
270