1 /*
2  * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  */
23 /*
24  * Copyright © 2003 Keith Packard
25  *
26  * Permission to use, copy, modify, distribute, and sell this software and its
27  * documentation for any purpose is hereby granted without fee, provided that
28  * the above copyright notice appear in all copies and that both that
29  * copyright notice and this permission notice appear in supporting
30  * documentation, and that the name of Keith Packard not be used in
31  * advertising or publicity pertaining to distribution of the software without
32  * specific, written prior permission.  Keith Packard makes no
33  * representations about the suitability of this software for any purpose.  It
34  * is provided "as is" without express or implied warranty.
35  *
36  * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
37  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
38  * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
39  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
40  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
41  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
42  * PERFORMANCE OF THIS SOFTWARE.
43  */
44 
45 #include "xcompositeint.h"
46 
47 XCompositeExtInfo XCompositeExtensionInfo;
48 
49 const char XCompositeExtensionName[] = COMPOSITE_NAME;
50 
51 /*
52  * XCompositeExtRemoveDisplay - remove the indicated display from the
53  * extension object. (Replaces XextRemoveDisplay.)
54  */
55 static int
XCompositeExtRemoveDisplay(XCompositeExtInfo * extinfo,Display * dpy)56 XCompositeExtRemoveDisplay (XCompositeExtInfo *extinfo, Display *dpy)
57 {
58     XCompositeExtDisplayInfo *info, *prev;
59 
60     /*
61      * locate this display and its back link so that it can be removed
62      */
63     _XLockMutex(_Xglobal_lock);
64     prev = NULL;
65     for (info = extinfo->head; info; info = info->next) {
66 	if (info->display == dpy) break;
67 	prev = info;
68     }
69     if (!info) {
70 	_XUnlockMutex(_Xglobal_lock);
71 	return 0;		/* hmm, actually an error */
72     }
73 
74     /*
75      * remove the display from the list; handles going to zero
76      */
77     if (prev)
78 	prev->next = info->next;
79     else
80 	extinfo->head = info->next;
81 
82     extinfo->ndisplays--;
83     if (info == extinfo->cur) extinfo->cur = NULL;  /* flush cache */
84     _XUnlockMutex(_Xglobal_lock);
85 
86     Xfree ((char *) info);
87     return 1;
88 }
89 
90 static int
XCompositeCloseDisplay(Display * dpy,XExtCodes * codes)91 XCompositeCloseDisplay (Display *dpy, XExtCodes *codes)
92 {
93     return XCompositeExtRemoveDisplay (&XCompositeExtensionInfo, dpy);
94 }
95 
96 /*
97  * XCompositeExtAddDisplay - add a display to this extension. (Replaces
98  * XextAddDisplay)
99  */
100 static XCompositeExtDisplayInfo *
XCompositeExtAddDisplay(XCompositeExtInfo * extinfo,Display * dpy,const char * ext_name)101 XCompositeExtAddDisplay (XCompositeExtInfo	*extinfo,
102 			 Display		*dpy,
103 			 const char		*ext_name)
104 {
105     XCompositeExtDisplayInfo    *info;
106 
107     info = (XCompositeExtDisplayInfo *) Xmalloc (sizeof (XCompositeExtDisplayInfo));
108     if (!info) return NULL;
109     info->display = dpy;
110 
111     info->codes = XInitExtension (dpy, ext_name);
112 
113     /*
114      * if the server has the extension, then we can initialize the
115      * appropriate function vectors
116      */
117     if (info->codes) {
118 	xCompositeQueryVersionReply	rep;
119 	xCompositeQueryVersionReq	*req;
120         XESetCloseDisplay (dpy, info->codes->extension,
121                            XCompositeCloseDisplay);
122 	/*
123 	 * Get the version info
124 	 */
125 	LockDisplay (dpy);
126 	GetReq (CompositeQueryVersion, req);
127 	req->reqType = info->codes->major_opcode;
128 	req->compositeReqType = X_CompositeQueryVersion;
129 	req->majorVersion = COMPOSITE_MAJOR;
130 	req->minorVersion = COMPOSITE_MINOR;
131 	if (!_XReply (dpy, (xReply *) &rep, 0, xTrue))
132 	{
133 	    UnlockDisplay (dpy);
134 	    SyncHandle ();
135 	    Xfree(info);
136 	    return NULL;
137 	}
138 	info->major_version = rep.majorVersion;
139 	info->minor_version = rep.minorVersion;
140 	UnlockDisplay (dpy);
141 	SyncHandle ();
142     } else {
143 	/* The server doesn't have this extension.
144 	 * Use a private Xlib-internal extension to hang the close_display
145 	 * hook on so that the "cache" (extinfo->cur) is properly cleaned.
146 	 * (XBUG 7955)
147 	 */
148 	XExtCodes *codes = XAddExtension(dpy);
149 	if (!codes) {
150 	    Xfree(info);
151 	    return NULL;
152 	}
153         XESetCloseDisplay (dpy, codes->extension, XCompositeCloseDisplay);
154     }
155 
156     /*
157      * now, chain it onto the list
158      */
159     _XLockMutex(_Xglobal_lock);
160     info->next = extinfo->head;
161     extinfo->head = info;
162     extinfo->cur = info;
163     extinfo->ndisplays++;
164     _XUnlockMutex(_Xglobal_lock);
165     return info;
166 }
167 
168 /*
169  * XCompositeExtFindDisplay - look for a display in this extension; keeps a
170  * cache of the most-recently used for efficiency. (Replaces
171  * XextFindDisplay.)
172  */
173 static XCompositeExtDisplayInfo *
XCompositeExtFindDisplay(XCompositeExtInfo * extinfo,Display * dpy)174 XCompositeExtFindDisplay (XCompositeExtInfo *extinfo,
175 		      Display	    *dpy)
176 {
177     XCompositeExtDisplayInfo *info;
178 
179     /*
180      * see if this was the most recently accessed display
181      */
182     if ((info = extinfo->cur) && info->display == dpy)
183 	return info;
184 
185     /*
186      * look for display in list
187      */
188     _XLockMutex(_Xglobal_lock);
189     for (info = extinfo->head; info; info = info->next) {
190 	if (info->display == dpy) {
191 	    extinfo->cur = info;     /* cache most recently used */
192 	    _XUnlockMutex(_Xglobal_lock);
193 	    return info;
194 	}
195     }
196     _XUnlockMutex(_Xglobal_lock);
197 
198     return NULL;
199 }
200 
201 XCompositeExtDisplayInfo *
XCompositeFindDisplay(Display * dpy)202 XCompositeFindDisplay (Display *dpy)
203 {
204     XCompositeExtDisplayInfo *info;
205 
206     info = XCompositeExtFindDisplay (&XCompositeExtensionInfo, dpy);
207     if (!info)
208 	info = XCompositeExtAddDisplay (&XCompositeExtensionInfo, dpy,
209 				    XCompositeExtensionName);
210     return info;
211 }
212 
213 
214 Bool
XCompositeQueryExtension(Display * dpy,int * event_base_return,int * error_base_return)215 XCompositeQueryExtension (Display *dpy,
216 			  int *event_base_return,
217 			  int *error_base_return)
218 {
219     XCompositeExtDisplayInfo *info = XCompositeFindDisplay (dpy);
220 
221     if (XCompositeHasExtension(info))
222     {
223 	*event_base_return = info->codes->first_event;
224 	*error_base_return = info->codes->first_error;
225 	return True;
226     }
227     else
228 	return False;
229 }
230 
231 Status
XCompositeQueryVersion(Display * dpy,int * major_version_return,int * minor_version_return)232 XCompositeQueryVersion (Display *dpy,
233 		    int	    *major_version_return,
234 		    int	    *minor_version_return)
235 {
236     XCompositeExtDisplayInfo	*info = XCompositeFindDisplay (dpy);
237 
238     XCompositeCheckExtension (dpy, info, 0);
239     *major_version_return = info->major_version;
240     *minor_version_return = info->minor_version;
241     return 1;
242 }
243 
244 int
XCompositeVersion(void)245 XCompositeVersion (void)
246 {
247     return XCOMPOSITE_VERSION;
248 }
249 
250 void
XCompositeRedirectWindow(Display * dpy,Window window,int update)251 XCompositeRedirectWindow (Display *dpy, Window window, int update)
252 {
253     XCompositeExtDisplayInfo	    *info = XCompositeFindDisplay (dpy);
254     xCompositeRedirectWindowReq	    *req;
255 
256     XCompositeSimpleCheckExtension (dpy, info);
257     LockDisplay (dpy);
258     GetReq (CompositeRedirectWindow, req);
259     req->reqType = info->codes->major_opcode;
260     req->compositeReqType = X_CompositeRedirectWindow;
261     req->window = window;
262     req->update = update;
263     UnlockDisplay (dpy);
264     SyncHandle ();
265 }
266 
267 void
XCompositeRedirectSubwindows(Display * dpy,Window window,int update)268 XCompositeRedirectSubwindows (Display *dpy, Window window, int update)
269 {
270     XCompositeExtDisplayInfo	    *info = XCompositeFindDisplay (dpy);
271     xCompositeRedirectSubwindowsReq *req;
272 
273     XCompositeSimpleCheckExtension (dpy, info);
274     LockDisplay (dpy);
275     GetReq (CompositeRedirectSubwindows, req);
276     req->reqType = info->codes->major_opcode;
277     req->compositeReqType = X_CompositeRedirectSubwindows;
278     req->window = window;
279     req->update = update;
280     UnlockDisplay (dpy);
281     SyncHandle ();
282 }
283 
284 void
XCompositeUnredirectWindow(Display * dpy,Window window,int update)285 XCompositeUnredirectWindow (Display *dpy, Window window, int update)
286 {
287     XCompositeExtDisplayInfo	    *info = XCompositeFindDisplay (dpy);
288     xCompositeUnredirectWindowReq   *req;
289 
290     XCompositeSimpleCheckExtension (dpy, info);
291     LockDisplay (dpy);
292     GetReq (CompositeUnredirectWindow, req);
293     req->reqType = info->codes->major_opcode;
294     req->compositeReqType = X_CompositeUnredirectWindow;
295     req->window = window;
296     req->update = update;
297     UnlockDisplay (dpy);
298     SyncHandle ();
299 }
300 
301 void
XCompositeUnredirectSubwindows(Display * dpy,Window window,int update)302 XCompositeUnredirectSubwindows (Display *dpy, Window window, int update)
303 {
304     XCompositeExtDisplayInfo		*info = XCompositeFindDisplay (dpy);
305     xCompositeUnredirectSubwindowsReq	*req;
306 
307     XCompositeSimpleCheckExtension (dpy, info);
308     LockDisplay (dpy);
309     GetReq (CompositeUnredirectSubwindows, req);
310     req->reqType = info->codes->major_opcode;
311     req->compositeReqType = X_CompositeUnredirectSubwindows;
312     req->window = window;
313     req->update = update;
314     UnlockDisplay (dpy);
315     SyncHandle ();
316 }
317 
318 XserverRegion
XCompositeCreateRegionFromBorderClip(Display * dpy,Window window)319 XCompositeCreateRegionFromBorderClip (Display *dpy, Window window)
320 {
321     XCompositeExtDisplayInfo		    *info = XCompositeFindDisplay (dpy);
322     xCompositeCreateRegionFromBorderClipReq *req;
323     XserverRegion			    region;
324 
325     XCompositeCheckExtension (dpy, info, 0);
326     LockDisplay (dpy);
327     GetReq (CompositeCreateRegionFromBorderClip, req);
328     req->reqType = info->codes->major_opcode;
329     req->compositeReqType = X_CompositeCreateRegionFromBorderClip;
330     req->window = window;
331     region = req->region = XAllocID (dpy);
332     UnlockDisplay (dpy);
333     SyncHandle ();
334     return region;
335 }
336 
337 Pixmap
XCompositeNameWindowPixmap(Display * dpy,Window window)338 XCompositeNameWindowPixmap (Display *dpy, Window window)
339 {
340     XCompositeExtDisplayInfo	    *info = XCompositeFindDisplay (dpy);
341     xCompositeNameWindowPixmapReq   *req;
342     Pixmap			    pixmap;
343 
344     XCompositeCheckExtension (dpy, info, 0);
345     LockDisplay (dpy);
346     GetReq (CompositeNameWindowPixmap, req);
347     req->reqType = info->codes->major_opcode;
348     req->compositeReqType = X_CompositeNameWindowPixmap;
349     req->window = window;
350     pixmap = req->pixmap = XAllocID (dpy);
351     UnlockDisplay (dpy);
352     SyncHandle ();
353     return pixmap;
354 }
355 
356 Window
XCompositeGetOverlayWindow(Display * dpy,Window window)357 XCompositeGetOverlayWindow (Display *dpy, Window window)
358 {
359     XCompositeExtDisplayInfo	    *info = XCompositeFindDisplay (dpy);
360     xCompositeGetOverlayWindowReq   *req;
361     xCompositeGetOverlayWindowReply rep;
362 
363     XCompositeCheckExtension (dpy, info, 0);
364     LockDisplay (dpy);
365     GetReq (CompositeGetOverlayWindow, req);
366     req->reqType = info->codes->major_opcode;
367     req->compositeReqType = X_CompositeGetOverlayWindow;
368     req->window = window;
369     if (!_XReply (dpy, (xReply *) &rep, 0, xFalse))
370     {
371 	UnlockDisplay (dpy);
372 	SyncHandle ();
373 	return 0;
374     }
375 
376     UnlockDisplay (dpy);
377     SyncHandle ();
378 
379     return rep.overlayWin;
380 }
381 
382 void
XCompositeReleaseOverlayWindow(Display * dpy,Window window)383 XCompositeReleaseOverlayWindow (Display *dpy, Window window)
384 {
385     XCompositeExtDisplayInfo	    *info = XCompositeFindDisplay (dpy);
386     xCompositeReleaseOverlayWindowReq   *req;
387 
388     XCompositeSimpleCheckExtension (dpy, info);
389     LockDisplay (dpy);
390     GetReq (CompositeReleaseOverlayWindow, req);
391     req->reqType = info->codes->major_opcode;
392     req->compositeReqType = X_CompositeReleaseOverlayWindow;
393     req->window = window;
394     UnlockDisplay (dpy);
395     SyncHandle ();
396 }
397