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