1af7c02bdSmrg/*
2af7c02bdSmrg * Copyright © 2003 Keith Packard
3af7c02bdSmrg * Copyright © 2007 Eric Anholt
4af7c02bdSmrg *
5af7c02bdSmrg * Permission to use, copy, modify, distribute, and sell this software and its
6af7c02bdSmrg * documentation for any purpose is hereby granted without fee, provided that
7af7c02bdSmrg * the above copyright notice appear in all copies and that both that
8af7c02bdSmrg * copyright notice and this permission notice appear in supporting
9af7c02bdSmrg * documentation, and that the name of Keith Packard not be used in
10af7c02bdSmrg * advertising or publicity pertaining to distribution of the software without
11af7c02bdSmrg * specific, written prior permission.  Keith Packard makes no
12af7c02bdSmrg * representations about the suitability of this software for any purpose.  It
13af7c02bdSmrg * is provided "as is" without express or implied warranty.
14af7c02bdSmrg *
15af7c02bdSmrg * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16af7c02bdSmrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
17af7c02bdSmrg * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18af7c02bdSmrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
19af7c02bdSmrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
20af7c02bdSmrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
21af7c02bdSmrg * PERFORMANCE OF THIS SOFTWARE.
22af7c02bdSmrg */
23af7c02bdSmrg
24af7c02bdSmrg#ifdef HAVE_CONFIG_H
25af7c02bdSmrg#include <config.h>
26af7c02bdSmrg#endif
27af7c02bdSmrg#include "xdamageint.h"
286c9573adSmrg#include <X11/Xfuncproto.h>
29af7c02bdSmrg
30af7c02bdSmrgXDamageExtInfo XDamageExtensionInfo;
31af7c02bdSmrg
32af7c02bdSmrgconst char XDamageExtensionName[] = DAMAGE_NAME;
33af7c02bdSmrg
34af7c02bdSmrgstatic int
35af7c02bdSmrgXDamageCloseDisplay (Display *dpy, XExtCodes *codes);
366dda92f9Smrg
37af7c02bdSmrgstatic Bool
38af7c02bdSmrgXDamageWireToEvent(Display *dpy, XEvent *event, xEvent *wire);
39af7c02bdSmrg
40af7c02bdSmrgstatic Status
41af7c02bdSmrgXDamageEventToWire(Display *dpy, XEvent *event, xEvent *wire);
42af7c02bdSmrg
43af7c02bdSmrg/*
44af7c02bdSmrg * XDamageExtAddDisplay - add a display to this extension. (Replaces
45af7c02bdSmrg * XextAddDisplay)
46af7c02bdSmrg */
47af7c02bdSmrgstatic XDamageExtDisplayInfo *
48af7c02bdSmrgXDamageExtAddDisplay (XDamageExtInfo	*extinfo,
49af7c02bdSmrg                      Display		*dpy,
50af7c02bdSmrg                      const char	*ext_name)
51af7c02bdSmrg{
52af7c02bdSmrg    XDamageExtDisplayInfo    *info;
53af7c02bdSmrg
546c9573adSmrg    info = Xmalloc (sizeof (XDamageExtDisplayInfo));
55af7c02bdSmrg    if (!info) return NULL;
56af7c02bdSmrg    info->display = dpy;
57af7c02bdSmrg
58af7c02bdSmrg    info->codes = XInitExtension (dpy, ext_name);
59af7c02bdSmrg
60af7c02bdSmrg    /*
616dda92f9Smrg     * if the server has the extension, then we can initialize the
62af7c02bdSmrg     * appropriate function vectors
63af7c02bdSmrg     */
64af7c02bdSmrg    if (info->codes) {
65af7c02bdSmrg	xDamageQueryVersionReply	rep;
66af7c02bdSmrg	xDamageQueryVersionReq	*req;
676dda92f9Smrg        XESetCloseDisplay (dpy, info->codes->extension,
68af7c02bdSmrg                           XDamageCloseDisplay);
696c9573adSmrg	for (int ev = info->codes->first_event;
70af7c02bdSmrg	     ev < info->codes->first_event + XDamageNumberEvents;
71af7c02bdSmrg	     ev++)
72af7c02bdSmrg	{
73af7c02bdSmrg	    XESetWireToEvent (dpy, ev, XDamageWireToEvent);
74af7c02bdSmrg	    XESetEventToWire (dpy, ev, XDamageEventToWire);
75af7c02bdSmrg	}
76af7c02bdSmrg	/*
77af7c02bdSmrg	 * Get the version info
78af7c02bdSmrg	 */
79af7c02bdSmrg	LockDisplay (dpy);
80af7c02bdSmrg	GetReq (DamageQueryVersion, req);
816c9573adSmrg	req->reqType = (CARD8) info->codes->major_opcode;
82af7c02bdSmrg	req->damageReqType = X_DamageQueryVersion;
83af7c02bdSmrg	req->majorVersion = DAMAGE_MAJOR;
84af7c02bdSmrg	req->minorVersion = DAMAGE_MINOR;
856dda92f9Smrg	if (!_XReply (dpy, (xReply *) &rep, 0, xTrue))
86af7c02bdSmrg	{
87af7c02bdSmrg	    UnlockDisplay (dpy);
88af7c02bdSmrg	    SyncHandle ();
89af7c02bdSmrg	    Xfree(info);
9081c81b28Smrg	    return NULL;
91af7c02bdSmrg	}
92af7c02bdSmrg	info->major_version = rep.majorVersion;
93af7c02bdSmrg	info->minor_version = rep.minorVersion;
94af7c02bdSmrg	UnlockDisplay (dpy);
95417cc7e8Smrg	SyncHandle ();
96af7c02bdSmrg    } else {
97af7c02bdSmrg	/* The server doesn't have this extension.
98af7c02bdSmrg	 * Use a private Xlib-internal extension to hang the close_display
99af7c02bdSmrg	 * hook on so that the "cache" (extinfo->cur) is properly cleaned.
100af7c02bdSmrg	 * (XBUG 7955)
101af7c02bdSmrg	 */
102af7c02bdSmrg	XExtCodes *codes = XAddExtension(dpy);
103af7c02bdSmrg	if (!codes) {
1046c9573adSmrg	    Xfree(info);
105af7c02bdSmrg	    return NULL;
106af7c02bdSmrg	}
107af7c02bdSmrg        XESetCloseDisplay (dpy, codes->extension, XDamageCloseDisplay);
108af7c02bdSmrg    }
109af7c02bdSmrg
110af7c02bdSmrg    /*
111af7c02bdSmrg     * now, chain it onto the list
112af7c02bdSmrg     */
113af7c02bdSmrg    _XLockMutex(_Xglobal_lock);
114af7c02bdSmrg    info->next = extinfo->head;
115af7c02bdSmrg    extinfo->head = info;
116af7c02bdSmrg    extinfo->cur = info;
117af7c02bdSmrg    extinfo->ndisplays++;
118af7c02bdSmrg    _XUnlockMutex(_Xglobal_lock);
119af7c02bdSmrg    return info;
120af7c02bdSmrg}
121af7c02bdSmrg
122af7c02bdSmrg
123af7c02bdSmrg/*
124af7c02bdSmrg * XDamageExtRemoveDisplay - remove the indicated display from the
125af7c02bdSmrg * extension object. (Replaces XextRemoveDisplay.)
126af7c02bdSmrg */
1276dda92f9Smrgstatic int
1286c9573adSmrgXDamageExtRemoveDisplay (XDamageExtInfo *extinfo, const Display *dpy)
129af7c02bdSmrg{
130af7c02bdSmrg    XDamageExtDisplayInfo *info, *prev;
131af7c02bdSmrg
132af7c02bdSmrg    /*
133af7c02bdSmrg     * locate this display and its back link so that it can be removed
134af7c02bdSmrg     */
135af7c02bdSmrg    _XLockMutex(_Xglobal_lock);
136af7c02bdSmrg    prev = NULL;
137af7c02bdSmrg    for (info = extinfo->head; info; info = info->next) {
138af7c02bdSmrg	if (info->display == dpy) break;
139af7c02bdSmrg	prev = info;
140af7c02bdSmrg    }
141af7c02bdSmrg    if (!info) {
142af7c02bdSmrg	_XUnlockMutex(_Xglobal_lock);
143af7c02bdSmrg	return 0;		/* hmm, actually an error */
144af7c02bdSmrg    }
145af7c02bdSmrg
146af7c02bdSmrg    /*
147af7c02bdSmrg     * remove the display from the list; handles going to zero
148af7c02bdSmrg     */
149af7c02bdSmrg    if (prev)
150af7c02bdSmrg	prev->next = info->next;
151af7c02bdSmrg    else
152af7c02bdSmrg	extinfo->head = info->next;
153af7c02bdSmrg
154af7c02bdSmrg    extinfo->ndisplays--;
155af7c02bdSmrg    if (info == extinfo->cur) extinfo->cur = NULL;  /* flush cache */
156af7c02bdSmrg    _XUnlockMutex(_Xglobal_lock);
157af7c02bdSmrg
1586c9573adSmrg    Xfree (info);
159af7c02bdSmrg    return 1;
160af7c02bdSmrg}
161af7c02bdSmrg
162af7c02bdSmrg/*
163af7c02bdSmrg * XDamageExtFindDisplay - look for a display in this extension; keeps a
164af7c02bdSmrg * cache of the most-recently used for efficiency. (Replaces
165af7c02bdSmrg * XextFindDisplay.)
166af7c02bdSmrg */
167af7c02bdSmrgstatic XDamageExtDisplayInfo *
1686dda92f9SmrgXDamageExtFindDisplay (XDamageExtInfo *extinfo,
1696c9573adSmrg		       const Display  *dpy)
170af7c02bdSmrg{
171af7c02bdSmrg    XDamageExtDisplayInfo *info;
172af7c02bdSmrg
173af7c02bdSmrg    /*
174af7c02bdSmrg     * see if this was the most recently accessed display
175af7c02bdSmrg     */
1766dda92f9Smrg    if ((info = extinfo->cur) && info->display == dpy)
177af7c02bdSmrg	return info;
178af7c02bdSmrg
179af7c02bdSmrg    /*
180af7c02bdSmrg     * look for display in list
181af7c02bdSmrg     */
182af7c02bdSmrg    _XLockMutex(_Xglobal_lock);
183af7c02bdSmrg    for (info = extinfo->head; info; info = info->next) {
184af7c02bdSmrg	if (info->display == dpy) {
185af7c02bdSmrg	    extinfo->cur = info;     /* cache most recently used */
186af7c02bdSmrg	    _XUnlockMutex(_Xglobal_lock);
187af7c02bdSmrg	    return info;
188af7c02bdSmrg	}
189af7c02bdSmrg    }
190af7c02bdSmrg    _XUnlockMutex(_Xglobal_lock);
191af7c02bdSmrg
192af7c02bdSmrg    return NULL;
193af7c02bdSmrg}
194af7c02bdSmrg
195af7c02bdSmrgXDamageExtDisplayInfo *
196af7c02bdSmrgXDamageFindDisplay (Display *dpy)
197af7c02bdSmrg{
198af7c02bdSmrg    XDamageExtDisplayInfo *info;
199af7c02bdSmrg
200af7c02bdSmrg    info = XDamageExtFindDisplay (&XDamageExtensionInfo, dpy);
201af7c02bdSmrg    if (!info)
2026dda92f9Smrg	info = XDamageExtAddDisplay (&XDamageExtensionInfo, dpy,
203af7c02bdSmrg				    XDamageExtensionName);
204af7c02bdSmrg    return info;
205af7c02bdSmrg}
2066dda92f9Smrg
207af7c02bdSmrgstatic int
2086c9573adSmrgXDamageCloseDisplay (Display *dpy, _X_UNUSED XExtCodes *codes)
209af7c02bdSmrg{
210af7c02bdSmrg    return XDamageExtRemoveDisplay (&XDamageExtensionInfo, dpy);
211af7c02bdSmrg}
212af7c02bdSmrg
213af7c02bdSmrgstatic Bool
214af7c02bdSmrgXDamageWireToEvent(Display *dpy, XEvent *event, xEvent *wire)
215af7c02bdSmrg{
216af7c02bdSmrg    XDamageExtDisplayInfo *info = XDamageFindDisplay(dpy);
217af7c02bdSmrg
218af7c02bdSmrg    XDamageCheckExtension(dpy, info, False);
219af7c02bdSmrg
220af7c02bdSmrg    switch ((wire->u.u.type & 0x7F) - info->codes->first_event)
221af7c02bdSmrg    {
222af7c02bdSmrg    case XDamageNotify: {
223af7c02bdSmrg	XDamageNotifyEvent *aevent = (XDamageNotifyEvent *) event;
224af7c02bdSmrg	xDamageNotifyEvent *awire = (xDamageNotifyEvent *) wire;
225af7c02bdSmrg
226af7c02bdSmrg	aevent->type = awire->type & 0x7F;
227af7c02bdSmrg	aevent->serial = _XSetLastRequestRead(dpy,
228af7c02bdSmrg					      (xGenericReply *) wire);
229af7c02bdSmrg	aevent->send_event = (awire->type & 0x80) != 0;
230af7c02bdSmrg	aevent->display = dpy;
231af7c02bdSmrg	aevent->drawable = awire->drawable;
232af7c02bdSmrg	aevent->damage = awire->damage;
23381c81b28Smrg	aevent->level = awire->level & ~DamageNotifyMore;
23481c81b28Smrg	aevent->more = (awire->level & DamageNotifyMore) ? True : False;
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;
2646c9573adSmrg	awire->type = (CARD8) aevent->type | (aevent->send_event ? 0x80 : 0);
2656c9573adSmrg	awire->drawable = (CARD32) aevent->drawable;
2666c9573adSmrg	awire->damage = (CARD32) aevent->damage;
2676c9573adSmrg	awire->level = (CARD8) aevent->level | (aevent->more ? DamageNotifyMore : 0);
2686c9573adSmrg	awire->timestamp = (CARD32) 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
2836dda92f9SmrgBool
28481c81b28SmrgXDamageQueryExtension (Display *dpy,
28581c81b28Smrg			int *event_base_return,
28681c81b28Smrg			int *error_base_return)
287af7c02bdSmrg{
288af7c02bdSmrg    XDamageExtDisplayInfo *info = XDamageFindDisplay (dpy);
289af7c02bdSmrg
2906dda92f9Smrg    if (XDamageHasExtension(info))
291af7c02bdSmrg    {
29281c81b28Smrg	*event_base_return = info->codes->first_event;
29381c81b28Smrg	*error_base_return = info->codes->first_error;
294af7c02bdSmrg	return True;
2956dda92f9Smrg    }
296af7c02bdSmrg    else
297af7c02bdSmrg	return False;
298af7c02bdSmrg}
299af7c02bdSmrg
3006dda92f9SmrgStatus
301af7c02bdSmrgXDamageQueryVersion (Display *dpy,
30281c81b28Smrg		    int	    *major_version_return,
30381c81b28Smrg		    int	    *minor_version_return)
304af7c02bdSmrg{
305af7c02bdSmrg    XDamageExtDisplayInfo	*info = XDamageFindDisplay (dpy);
306af7c02bdSmrg
307af7c02bdSmrg    XDamageCheckExtension (dpy, info, 0);
308af7c02bdSmrg
30981c81b28Smrg    *major_version_return = info->major_version;
31081c81b28Smrg    *minor_version_return = info->minor_version;
311af7c02bdSmrg    return 1;
312af7c02bdSmrg}
313af7c02bdSmrg
314af7c02bdSmrgDamage
315af7c02bdSmrgXDamageCreate (Display *dpy, Drawable drawable, int level)
316af7c02bdSmrg{
317af7c02bdSmrg    XDamageExtDisplayInfo	*info = XDamageFindDisplay (dpy);
318af7c02bdSmrg    xDamageCreateReq		*req;
319af7c02bdSmrg    Damage			damage;
320af7c02bdSmrg
321af7c02bdSmrg    XDamageCheckExtension (dpy, info, 0);
322af7c02bdSmrg    LockDisplay (dpy);
323af7c02bdSmrg    GetReq (DamageCreate, req);
3246c9573adSmrg    req->reqType = (CARD8) info->codes->major_opcode;
325af7c02bdSmrg    req->damageReqType = X_DamageCreate;
3266c9573adSmrg    damage = XAllocID (dpy);
3276c9573adSmrg    req->damage = (CARD32) damage;
3286c9573adSmrg    req->drawable = (CARD32) drawable;
3296c9573adSmrg    req->level = (CARD8) level;
330af7c02bdSmrg    UnlockDisplay (dpy);
331af7c02bdSmrg    SyncHandle ();
332af7c02bdSmrg    return damage;
333af7c02bdSmrg}
334af7c02bdSmrg
335af7c02bdSmrgvoid
336af7c02bdSmrgXDamageDestroy (Display *dpy, Damage damage)
337af7c02bdSmrg{
338af7c02bdSmrg    XDamageExtDisplayInfo	*info = XDamageFindDisplay (dpy);
339af7c02bdSmrg    xDamageDestroyReq		*req;
340af7c02bdSmrg
341af7c02bdSmrg    XDamageSimpleCheckExtension (dpy, info);
342af7c02bdSmrg    LockDisplay (dpy);
343af7c02bdSmrg    GetReq (DamageDestroy, req);
3446c9573adSmrg    req->reqType = (CARD8) info->codes->major_opcode;
345af7c02bdSmrg    req->damageReqType = X_DamageDestroy;
3466c9573adSmrg    req->damage = (CARD32) damage;
347af7c02bdSmrg    UnlockDisplay (dpy);
348af7c02bdSmrg    SyncHandle ();
349af7c02bdSmrg}
350af7c02bdSmrg
351af7c02bdSmrgvoid
3526dda92f9SmrgXDamageSubtract (Display *dpy, Damage damage,
353af7c02bdSmrg		 XserverRegion repair, XserverRegion parts)
354af7c02bdSmrg{
355af7c02bdSmrg    XDamageExtDisplayInfo	*info = XDamageFindDisplay (dpy);
356af7c02bdSmrg    xDamageSubtractReq		*req;
357af7c02bdSmrg
358af7c02bdSmrg    XDamageSimpleCheckExtension (dpy, info);
359af7c02bdSmrg    LockDisplay (dpy);
360af7c02bdSmrg    GetReq (DamageSubtract, req);
3616c9573adSmrg    req->reqType = (CARD8) info->codes->major_opcode;
362af7c02bdSmrg    req->damageReqType = X_DamageSubtract;
3636c9573adSmrg    req->damage = (CARD32) damage;
3646c9573adSmrg    req->repair = (CARD32) repair;
3656c9573adSmrg    req->parts = (CARD32) parts;
366af7c02bdSmrg    UnlockDisplay (dpy);
367af7c02bdSmrg    SyncHandle ();
368af7c02bdSmrg}
369af7c02bdSmrg
370af7c02bdSmrgvoid
371af7c02bdSmrgXDamageAdd (Display *dpy, Drawable drawable, XserverRegion region)
372af7c02bdSmrg{
373af7c02bdSmrg    XDamageExtDisplayInfo	*info = XDamageFindDisplay (dpy);
374af7c02bdSmrg    xDamageAddReq		*req;
375af7c02bdSmrg
376af7c02bdSmrg    XDamageSimpleCheckExtension (dpy, info);
377af7c02bdSmrg    LockDisplay (dpy);
378af7c02bdSmrg    GetReq (DamageAdd, req);
3796c9573adSmrg    req->reqType = (CARD8) info->codes->major_opcode;
380af7c02bdSmrg    req->damageReqType = X_DamageAdd;
3816c9573adSmrg    req->drawable = (CARD32) drawable;
3826c9573adSmrg    req->region = (CARD32) region;
383af7c02bdSmrg
384af7c02bdSmrg    UnlockDisplay (dpy);
385af7c02bdSmrg    SyncHandle ();
386af7c02bdSmrg}
387