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