1 /*
2  * Copyright © 2003 Keith Packard
3  * Copyright © 2007 Eric Anholt
4  *
5  * Permission to use, copy, modify, distribute, and sell this software and its
6  * documentation for any purpose is hereby granted without fee, provided that
7  * the above copyright notice appear in all copies and that both that
8  * copyright notice and this permission notice appear in supporting
9  * documentation, and that the name of Keith Packard not be used in
10  * advertising or publicity pertaining to distribution of the software without
11  * specific, written prior permission.  Keith Packard makes no
12  * representations about the suitability of this software for any purpose.  It
13  * is provided "as is" without express or implied warranty.
14  *
15  * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
17  * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
19  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
20  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
21  * PERFORMANCE OF THIS SOFTWARE.
22  */
23 
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27 #include "xdamageint.h"
28 
29 XDamageExtInfo XDamageExtensionInfo;
30 
31 const char XDamageExtensionName[] = DAMAGE_NAME;
32 
33 static int
34 XDamageCloseDisplay (Display *dpy, XExtCodes *codes);
35 
36 static Bool
37 XDamageWireToEvent(Display *dpy, XEvent *event, xEvent *wire);
38 
39 static Status
40 XDamageEventToWire(Display *dpy, XEvent *event, xEvent *wire);
41 
42 /*
43  * XDamageExtAddDisplay - add a display to this extension. (Replaces
44  * XextAddDisplay)
45  */
46 static XDamageExtDisplayInfo *
XDamageExtAddDisplay(XDamageExtInfo * extinfo,Display * dpy,const char * ext_name)47 XDamageExtAddDisplay (XDamageExtInfo	*extinfo,
48                       Display		*dpy,
49                       const char	*ext_name)
50 {
51     XDamageExtDisplayInfo    *info;
52     int			    ev;
53 
54     info = (XDamageExtDisplayInfo *) Xmalloc (sizeof (XDamageExtDisplayInfo));
55     if (!info) return NULL;
56     info->display = dpy;
57 
58     info->codes = XInitExtension (dpy, ext_name);
59 
60     /*
61      * if the server has the extension, then we can initialize the
62      * appropriate function vectors
63      */
64     if (info->codes) {
65 	xDamageQueryVersionReply	rep;
66 	xDamageQueryVersionReq	*req;
67         XESetCloseDisplay (dpy, info->codes->extension,
68                            XDamageCloseDisplay);
69 	for (ev = info->codes->first_event;
70 	     ev < info->codes->first_event + XDamageNumberEvents;
71 	     ev++)
72 	{
73 	    XESetWireToEvent (dpy, ev, XDamageWireToEvent);
74 	    XESetEventToWire (dpy, ev, XDamageEventToWire);
75 	}
76 	/*
77 	 * Get the version info
78 	 */
79 	LockDisplay (dpy);
80 	GetReq (DamageQueryVersion, req);
81 	req->reqType = info->codes->major_opcode;
82 	req->damageReqType = X_DamageQueryVersion;
83 	req->majorVersion = DAMAGE_MAJOR;
84 	req->minorVersion = DAMAGE_MINOR;
85 	if (!_XReply (dpy, (xReply *) &rep, 0, xTrue))
86 	{
87 	    UnlockDisplay (dpy);
88 	    SyncHandle ();
89 	    Xfree(info);
90 	    return NULL;
91 	}
92 	info->major_version = rep.majorVersion;
93 	info->minor_version = rep.minorVersion;
94 	UnlockDisplay (dpy);
95 	SyncHandle ();
96     } else {
97 	/* The server doesn't have this extension.
98 	 * Use a private Xlib-internal extension to hang the close_display
99 	 * hook on so that the "cache" (extinfo->cur) is properly cleaned.
100 	 * (XBUG 7955)
101 	 */
102 	XExtCodes *codes = XAddExtension(dpy);
103 	if (!codes) {
104 	    Xfree(info);
105 	    return NULL;
106 	}
107         XESetCloseDisplay (dpy, codes->extension, XDamageCloseDisplay);
108     }
109 
110     /*
111      * now, chain it onto the list
112      */
113     _XLockMutex(_Xglobal_lock);
114     info->next = extinfo->head;
115     extinfo->head = info;
116     extinfo->cur = info;
117     extinfo->ndisplays++;
118     _XUnlockMutex(_Xglobal_lock);
119     return info;
120 }
121 
122 
123 /*
124  * XDamageExtRemoveDisplay - remove the indicated display from the
125  * extension object. (Replaces XextRemoveDisplay.)
126  */
127 static int
XDamageExtRemoveDisplay(XDamageExtInfo * extinfo,Display * dpy)128 XDamageExtRemoveDisplay (XDamageExtInfo *extinfo, Display *dpy)
129 {
130     XDamageExtDisplayInfo *info, *prev;
131 
132     /*
133      * locate this display and its back link so that it can be removed
134      */
135     _XLockMutex(_Xglobal_lock);
136     prev = NULL;
137     for (info = extinfo->head; info; info = info->next) {
138 	if (info->display == dpy) break;
139 	prev = info;
140     }
141     if (!info) {
142 	_XUnlockMutex(_Xglobal_lock);
143 	return 0;		/* hmm, actually an error */
144     }
145 
146     /*
147      * remove the display from the list; handles going to zero
148      */
149     if (prev)
150 	prev->next = info->next;
151     else
152 	extinfo->head = info->next;
153 
154     extinfo->ndisplays--;
155     if (info == extinfo->cur) extinfo->cur = NULL;  /* flush cache */
156     _XUnlockMutex(_Xglobal_lock);
157 
158     Xfree ((char *) info);
159     return 1;
160 }
161 
162 /*
163  * XDamageExtFindDisplay - look for a display in this extension; keeps a
164  * cache of the most-recently used for efficiency. (Replaces
165  * XextFindDisplay.)
166  */
167 static XDamageExtDisplayInfo *
XDamageExtFindDisplay(XDamageExtInfo * extinfo,Display * dpy)168 XDamageExtFindDisplay (XDamageExtInfo *extinfo,
169 		      Display	    *dpy)
170 {
171     XDamageExtDisplayInfo *info;
172 
173     /*
174      * see if this was the most recently accessed display
175      */
176     if ((info = extinfo->cur) && info->display == dpy)
177 	return info;
178 
179     /*
180      * look for display in list
181      */
182     _XLockMutex(_Xglobal_lock);
183     for (info = extinfo->head; info; info = info->next) {
184 	if (info->display == dpy) {
185 	    extinfo->cur = info;     /* cache most recently used */
186 	    _XUnlockMutex(_Xglobal_lock);
187 	    return info;
188 	}
189     }
190     _XUnlockMutex(_Xglobal_lock);
191 
192     return NULL;
193 }
194 
195 XDamageExtDisplayInfo *
XDamageFindDisplay(Display * dpy)196 XDamageFindDisplay (Display *dpy)
197 {
198     XDamageExtDisplayInfo *info;
199 
200     info = XDamageExtFindDisplay (&XDamageExtensionInfo, dpy);
201     if (!info)
202 	info = XDamageExtAddDisplay (&XDamageExtensionInfo, dpy,
203 				    XDamageExtensionName);
204     return info;
205 }
206 
207 static int
XDamageCloseDisplay(Display * dpy,XExtCodes * codes)208 XDamageCloseDisplay (Display *dpy, XExtCodes *codes)
209 {
210     return XDamageExtRemoveDisplay (&XDamageExtensionInfo, dpy);
211 }
212 
213 static Bool
XDamageWireToEvent(Display * dpy,XEvent * event,xEvent * wire)214 XDamageWireToEvent(Display *dpy, XEvent *event, xEvent *wire)
215 {
216     XDamageExtDisplayInfo *info = XDamageFindDisplay(dpy);
217 
218     XDamageCheckExtension(dpy, info, False);
219 
220     switch ((wire->u.u.type & 0x7F) - info->codes->first_event)
221     {
222     case XDamageNotify: {
223 	XDamageNotifyEvent *aevent = (XDamageNotifyEvent *) event;
224 	xDamageNotifyEvent *awire = (xDamageNotifyEvent *) wire;
225 
226 	aevent->type = awire->type & 0x7F;
227 	aevent->serial = _XSetLastRequestRead(dpy,
228 					      (xGenericReply *) wire);
229 	aevent->send_event = (awire->type & 0x80) != 0;
230 	aevent->display = dpy;
231 	aevent->drawable = awire->drawable;
232 	aevent->damage = awire->damage;
233 	aevent->level = awire->level & ~DamageNotifyMore;
234 	aevent->more = (awire->level & DamageNotifyMore) ? True : False;
235 	aevent->timestamp = awire->timestamp;
236 	aevent->area.x = awire->area.x;
237 	aevent->area.y = awire->area.y;
238 	aevent->area.width = awire->area.width;
239 	aevent->area.height = awire->area.height;
240 	aevent->geometry.x = awire->geometry.x;
241 	aevent->geometry.y = awire->geometry.y;
242 	aevent->geometry.width = awire->geometry.width;
243 	aevent->geometry.height = awire->geometry.height;
244 	return True;
245     }
246     }
247     return False;
248 }
249 
250 static Status
XDamageEventToWire(Display * dpy,XEvent * event,xEvent * wire)251 XDamageEventToWire(Display *dpy, XEvent *event, xEvent *wire)
252 {
253     XDamageExtDisplayInfo *info = XDamageFindDisplay(dpy);
254 
255     XDamageCheckExtension(dpy, info, False);
256 
257     switch ((event->type & 0x7F) - info->codes->first_event)
258     {
259     case XDamageNotify: {
260 	XDamageNotifyEvent *aevent;
261 	xDamageNotifyEvent *awire;
262 	awire = (xDamageNotifyEvent *) wire;
263 	aevent = (XDamageNotifyEvent *) event;
264 	awire->type = aevent->type | (aevent->send_event ? 0x80 : 0);
265 	awire->drawable = aevent->drawable;
266 	awire->damage = aevent->damage;
267 	awire->level = aevent->level | (aevent->more ? DamageNotifyMore : 0);
268 	awire->timestamp = aevent->timestamp;
269 	awire->area.x = aevent->area.x;
270 	awire->area.y = aevent->area.y;
271 	awire->area.width = aevent->area.width;
272 	awire->area.height = aevent->area.height;
273 	awire->geometry.x = aevent->geometry.x;
274 	awire->geometry.y = aevent->geometry.y;
275 	awire->geometry.width = aevent->geometry.width;
276 	awire->geometry.height = aevent->geometry.height;
277 	return True;
278     }
279     }
280     return False;
281 }
282 
283 Bool
XDamageQueryExtension(Display * dpy,int * event_base_return,int * error_base_return)284 XDamageQueryExtension (Display *dpy,
285 			int *event_base_return,
286 			int *error_base_return)
287 {
288     XDamageExtDisplayInfo *info = XDamageFindDisplay (dpy);
289 
290     if (XDamageHasExtension(info))
291     {
292 	*event_base_return = info->codes->first_event;
293 	*error_base_return = info->codes->first_error;
294 	return True;
295     }
296     else
297 	return False;
298 }
299 
300 Status
XDamageQueryVersion(Display * dpy,int * major_version_return,int * minor_version_return)301 XDamageQueryVersion (Display *dpy,
302 		    int	    *major_version_return,
303 		    int	    *minor_version_return)
304 {
305     XDamageExtDisplayInfo	*info = XDamageFindDisplay (dpy);
306 
307     XDamageCheckExtension (dpy, info, 0);
308 
309     *major_version_return = info->major_version;
310     *minor_version_return = info->minor_version;
311     return 1;
312 }
313 
314 Damage
XDamageCreate(Display * dpy,Drawable drawable,int level)315 XDamageCreate (Display *dpy, Drawable drawable, int level)
316 {
317     XDamageExtDisplayInfo	*info = XDamageFindDisplay (dpy);
318     xDamageCreateReq		*req;
319     Damage			damage;
320 
321     XDamageCheckExtension (dpy, info, 0);
322     LockDisplay (dpy);
323     GetReq (DamageCreate, req);
324     req->reqType = info->codes->major_opcode;
325     req->damageReqType = X_DamageCreate;
326     req->damage = damage = XAllocID (dpy);
327     req->drawable = drawable;
328     req->level = level;
329     UnlockDisplay (dpy);
330     SyncHandle ();
331     return damage;
332 }
333 
334 void
XDamageDestroy(Display * dpy,Damage damage)335 XDamageDestroy (Display *dpy, Damage damage)
336 {
337     XDamageExtDisplayInfo	*info = XDamageFindDisplay (dpy);
338     xDamageDestroyReq		*req;
339 
340     XDamageSimpleCheckExtension (dpy, info);
341     LockDisplay (dpy);
342     GetReq (DamageDestroy, req);
343     req->reqType = info->codes->major_opcode;
344     req->damageReqType = X_DamageDestroy;
345     req->damage = damage;
346     UnlockDisplay (dpy);
347     SyncHandle ();
348 }
349 
350 void
XDamageSubtract(Display * dpy,Damage damage,XserverRegion repair,XserverRegion parts)351 XDamageSubtract (Display *dpy, Damage damage,
352 		 XserverRegion repair, XserverRegion parts)
353 {
354     XDamageExtDisplayInfo	*info = XDamageFindDisplay (dpy);
355     xDamageSubtractReq		*req;
356 
357     XDamageSimpleCheckExtension (dpy, info);
358     LockDisplay (dpy);
359     GetReq (DamageSubtract, req);
360     req->reqType = info->codes->major_opcode;
361     req->damageReqType = X_DamageSubtract;
362     req->damage = damage;
363     req->repair = repair;
364     req->parts = parts;
365     UnlockDisplay (dpy);
366     SyncHandle ();
367 }
368 
369 void
XDamageAdd(Display * dpy,Drawable drawable,XserverRegion region)370 XDamageAdd (Display *dpy, Drawable drawable, XserverRegion region)
371 {
372     XDamageExtDisplayInfo	*info = XDamageFindDisplay (dpy);
373     xDamageAddReq		*req;
374 
375     XDamageSimpleCheckExtension (dpy, info);
376     LockDisplay (dpy);
377     GetReq (DamageAdd, req);
378     req->reqType = info->codes->major_opcode;
379     req->damageReqType = X_DamageAdd;
380     req->drawable = drawable;
381     req->region = region;
382 
383     UnlockDisplay (dpy);
384     SyncHandle ();
385 }
386