Xdamage.c revision 81c81b28
1af7c02bdSmrg/*
281c81b28Smrg * $Id: Xdamage.c,v 1.1.1.2 2009/11/08 09:42:59 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);
9281c81b28Smrg	    return NULL;
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;
23481c81b28Smrg	aevent->level = awire->level & ~DamageNotifyMore;
23581c81b28Smrg	aevent->more = (awire->level & DamageNotifyMore) ? True : False;
236af7c02bdSmrg	aevent->timestamp = awire->timestamp;
237af7c02bdSmrg	aevent->area.x = awire->area.x;
238af7c02bdSmrg	aevent->area.y = awire->area.y;
239af7c02bdSmrg	aevent->area.width = awire->area.width;
240af7c02bdSmrg	aevent->area.height = awire->area.height;
241af7c02bdSmrg	aevent->geometry.x = awire->geometry.x;
242af7c02bdSmrg	aevent->geometry.y = awire->geometry.y;
243af7c02bdSmrg	aevent->geometry.width = awire->geometry.width;
244af7c02bdSmrg	aevent->geometry.height = awire->geometry.height;
245af7c02bdSmrg	return True;
246af7c02bdSmrg    }
247af7c02bdSmrg    }
248af7c02bdSmrg    return False;
249af7c02bdSmrg}
250af7c02bdSmrg
251af7c02bdSmrgstatic Status
252af7c02bdSmrgXDamageEventToWire(Display *dpy, XEvent *event, xEvent *wire)
253af7c02bdSmrg{
254af7c02bdSmrg    XDamageExtDisplayInfo *info = XDamageFindDisplay(dpy);
255af7c02bdSmrg
256af7c02bdSmrg    XDamageCheckExtension(dpy, info, False);
257af7c02bdSmrg
258af7c02bdSmrg    switch ((event->type & 0x7F) - info->codes->first_event)
259af7c02bdSmrg    {
260af7c02bdSmrg    case XDamageNotify: {
261af7c02bdSmrg	XDamageNotifyEvent *aevent;
262af7c02bdSmrg	xDamageNotifyEvent *awire;
263af7c02bdSmrg	awire = (xDamageNotifyEvent *) wire;
264af7c02bdSmrg	aevent = (XDamageNotifyEvent *) event;
265af7c02bdSmrg	awire->type = aevent->type | (aevent->send_event ? 0x80 : 0);
266af7c02bdSmrg	awire->drawable = aevent->drawable;
267af7c02bdSmrg	awire->damage = aevent->damage;
26881c81b28Smrg	awire->level = aevent->level | (aevent->more ? DamageNotifyMore : 0);
269af7c02bdSmrg	awire->timestamp = aevent->timestamp;
270af7c02bdSmrg	awire->area.x = aevent->area.x;
271af7c02bdSmrg	awire->area.y = aevent->area.y;
272af7c02bdSmrg	awire->area.width = aevent->area.width;
273af7c02bdSmrg	awire->area.height = aevent->area.height;
274af7c02bdSmrg	awire->geometry.x = aevent->geometry.x;
275af7c02bdSmrg	awire->geometry.y = aevent->geometry.y;
276af7c02bdSmrg	awire->geometry.width = aevent->geometry.width;
277af7c02bdSmrg	awire->geometry.height = aevent->geometry.height;
278af7c02bdSmrg	return True;
279af7c02bdSmrg    }
280af7c02bdSmrg    }
281af7c02bdSmrg    return False;
282af7c02bdSmrg}
283af7c02bdSmrg
284af7c02bdSmrgBool
28581c81b28SmrgXDamageQueryExtension (Display *dpy,
28681c81b28Smrg			int *event_base_return,
28781c81b28Smrg			int *error_base_return)
288af7c02bdSmrg{
289af7c02bdSmrg    XDamageExtDisplayInfo *info = XDamageFindDisplay (dpy);
290af7c02bdSmrg
291af7c02bdSmrg    if (XDamageHasExtension(info))
292af7c02bdSmrg    {
29381c81b28Smrg	*event_base_return = info->codes->first_event;
29481c81b28Smrg	*error_base_return = info->codes->first_error;
295af7c02bdSmrg	return True;
296af7c02bdSmrg    }
297af7c02bdSmrg    else
298af7c02bdSmrg	return False;
299af7c02bdSmrg}
300af7c02bdSmrg
301af7c02bdSmrgStatus
302af7c02bdSmrgXDamageQueryVersion (Display *dpy,
30381c81b28Smrg		    int	    *major_version_return,
30481c81b28Smrg		    int	    *minor_version_return)
305af7c02bdSmrg{
306af7c02bdSmrg    XDamageExtDisplayInfo	*info = XDamageFindDisplay (dpy);
307af7c02bdSmrg
308af7c02bdSmrg    XDamageCheckExtension (dpy, info, 0);
309af7c02bdSmrg
31081c81b28Smrg    *major_version_return = info->major_version;
31181c81b28Smrg    *minor_version_return = info->minor_version;
312af7c02bdSmrg    return 1;
313af7c02bdSmrg}
314af7c02bdSmrg
315af7c02bdSmrgDamage
316af7c02bdSmrgXDamageCreate (Display *dpy, Drawable drawable, int level)
317af7c02bdSmrg{
318af7c02bdSmrg    XDamageExtDisplayInfo	*info = XDamageFindDisplay (dpy);
319af7c02bdSmrg    xDamageCreateReq		*req;
320af7c02bdSmrg    Damage			damage;
321af7c02bdSmrg
322af7c02bdSmrg    XDamageCheckExtension (dpy, info, 0);
323af7c02bdSmrg    LockDisplay (dpy);
324af7c02bdSmrg    GetReq (DamageCreate, req);
325af7c02bdSmrg    req->reqType = info->codes->major_opcode;
326af7c02bdSmrg    req->damageReqType = X_DamageCreate;
327af7c02bdSmrg    req->damage = damage = XAllocID (dpy);
328af7c02bdSmrg    req->drawable = drawable;
329af7c02bdSmrg    req->level = 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);
344af7c02bdSmrg    req->reqType = info->codes->major_opcode;
345af7c02bdSmrg    req->damageReqType = X_DamageDestroy;
346af7c02bdSmrg    req->damage = damage;
347af7c02bdSmrg    UnlockDisplay (dpy);
348af7c02bdSmrg    SyncHandle ();
349af7c02bdSmrg}
350af7c02bdSmrg
351af7c02bdSmrgvoid
352af7c02bdSmrgXDamageSubtract (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);
361af7c02bdSmrg    req->reqType = info->codes->major_opcode;
362af7c02bdSmrg    req->damageReqType = X_DamageSubtract;
363af7c02bdSmrg    req->damage = damage;
364af7c02bdSmrg    req->repair = repair;
365af7c02bdSmrg    req->parts = 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);
379af7c02bdSmrg    req->reqType = info->codes->major_opcode;
380af7c02bdSmrg    req->damageReqType = X_DamageAdd;
381af7c02bdSmrg    req->drawable = drawable;
382af7c02bdSmrg    req->region = region;
383af7c02bdSmrg
384af7c02bdSmrg    UnlockDisplay (dpy);
385af7c02bdSmrg    SyncHandle ();
386af7c02bdSmrg}
387