Always call SyncHandle after issuing an X request.
[platform/upstream/libXdamage.git] / src / Xdamage.c
1 /*
2  * $Id$
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
31 XDamageExtInfo XDamageExtensionInfo;
32
33 const char XDamageExtensionName[] = DAMAGE_NAME;
34
35 static int
36 XDamageCloseDisplay (Display *dpy, XExtCodes *codes);
37     
38 static Bool
39 XDamageWireToEvent(Display *dpy, XEvent *event, xEvent *wire);
40
41 static Status
42 XDamageEventToWire(Display *dpy, XEvent *event, xEvent *wire);
43
44 /*
45  * XDamageExtAddDisplay - add a display to this extension. (Replaces
46  * XextAddDisplay)
47  */
48 static XDamageExtDisplayInfo *
49 XDamageExtAddDisplay (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 NULL;
93         }
94         info->major_version = rep.majorVersion;
95         info->minor_version = rep.minorVersion;
96         UnlockDisplay (dpy);
97         SyncHandle ();
98     } else {
99         /* The server doesn't have this extension.
100          * Use a private Xlib-internal extension to hang the close_display
101          * hook on so that the "cache" (extinfo->cur) is properly cleaned.
102          * (XBUG 7955)
103          */
104         XExtCodes *codes = XAddExtension(dpy);
105         if (!codes) {
106             XFree(info);
107             return NULL;
108         }
109         XESetCloseDisplay (dpy, codes->extension, XDamageCloseDisplay);
110     }
111
112     /*
113      * now, chain it onto the list
114      */
115     _XLockMutex(_Xglobal_lock);
116     info->next = extinfo->head;
117     extinfo->head = info;
118     extinfo->cur = info;
119     extinfo->ndisplays++;
120     _XUnlockMutex(_Xglobal_lock);
121     return info;
122 }
123
124
125 /*
126  * XDamageExtRemoveDisplay - remove the indicated display from the
127  * extension object. (Replaces XextRemoveDisplay.)
128  */
129 static int 
130 XDamageExtRemoveDisplay (XDamageExtInfo *extinfo, Display *dpy)
131 {
132     XDamageExtDisplayInfo *info, *prev;
133
134     /*
135      * locate this display and its back link so that it can be removed
136      */
137     _XLockMutex(_Xglobal_lock);
138     prev = NULL;
139     for (info = extinfo->head; info; info = info->next) {
140         if (info->display == dpy) break;
141         prev = info;
142     }
143     if (!info) {
144         _XUnlockMutex(_Xglobal_lock);
145         return 0;               /* hmm, actually an error */
146     }
147
148     /*
149      * remove the display from the list; handles going to zero
150      */
151     if (prev)
152         prev->next = info->next;
153     else
154         extinfo->head = info->next;
155
156     extinfo->ndisplays--;
157     if (info == extinfo->cur) extinfo->cur = NULL;  /* flush cache */
158     _XUnlockMutex(_Xglobal_lock);
159
160     Xfree ((char *) info);
161     return 1;
162 }
163
164 /*
165  * XDamageExtFindDisplay - look for a display in this extension; keeps a
166  * cache of the most-recently used for efficiency. (Replaces
167  * XextFindDisplay.)
168  */
169 static XDamageExtDisplayInfo *
170 XDamageExtFindDisplay (XDamageExtInfo *extinfo, 
171                       Display       *dpy)
172 {
173     XDamageExtDisplayInfo *info;
174
175     /*
176      * see if this was the most recently accessed display
177      */
178     if ((info = extinfo->cur) && info->display == dpy) 
179         return info;
180
181     /*
182      * look for display in list
183      */
184     _XLockMutex(_Xglobal_lock);
185     for (info = extinfo->head; info; info = info->next) {
186         if (info->display == dpy) {
187             extinfo->cur = info;     /* cache most recently used */
188             _XUnlockMutex(_Xglobal_lock);
189             return info;
190         }
191     }
192     _XUnlockMutex(_Xglobal_lock);
193
194     return NULL;
195 }
196
197 XDamageExtDisplayInfo *
198 XDamageFindDisplay (Display *dpy)
199 {
200     XDamageExtDisplayInfo *info;
201
202     info = XDamageExtFindDisplay (&XDamageExtensionInfo, dpy);
203     if (!info)
204         info = XDamageExtAddDisplay (&XDamageExtensionInfo, dpy, 
205                                     XDamageExtensionName);
206     return info;
207 }
208     
209 static int
210 XDamageCloseDisplay (Display *dpy, XExtCodes *codes)
211 {
212     return XDamageExtRemoveDisplay (&XDamageExtensionInfo, dpy);
213 }
214
215 static Bool
216 XDamageWireToEvent(Display *dpy, XEvent *event, xEvent *wire)
217 {
218     XDamageExtDisplayInfo *info = XDamageFindDisplay(dpy);
219
220     XDamageCheckExtension(dpy, info, False);
221
222     switch ((wire->u.u.type & 0x7F) - info->codes->first_event)
223     {
224     case XDamageNotify: {
225         XDamageNotifyEvent *aevent = (XDamageNotifyEvent *) event;
226         xDamageNotifyEvent *awire = (xDamageNotifyEvent *) wire;
227
228         aevent->type = awire->type & 0x7F;
229         aevent->serial = _XSetLastRequestRead(dpy,
230                                               (xGenericReply *) wire);
231         aevent->send_event = (awire->type & 0x80) != 0;
232         aevent->display = dpy;
233         aevent->drawable = awire->drawable;
234         aevent->damage = awire->damage;
235         aevent->level = awire->level & ~DamageNotifyMore;
236         aevent->more = (awire->level & DamageNotifyMore) ? True : False;
237         aevent->timestamp = awire->timestamp;
238         aevent->area.x = awire->area.x;
239         aevent->area.y = awire->area.y;
240         aevent->area.width = awire->area.width;
241         aevent->area.height = awire->area.height;
242         aevent->geometry.x = awire->geometry.x;
243         aevent->geometry.y = awire->geometry.y;
244         aevent->geometry.width = awire->geometry.width;
245         aevent->geometry.height = awire->geometry.height;
246         return True;
247     }
248     }
249     return False;
250 }
251
252 static Status
253 XDamageEventToWire(Display *dpy, XEvent *event, xEvent *wire)
254 {
255     XDamageExtDisplayInfo *info = XDamageFindDisplay(dpy);
256
257     XDamageCheckExtension(dpy, info, False);
258
259     switch ((event->type & 0x7F) - info->codes->first_event)
260     {
261     case XDamageNotify: {
262         XDamageNotifyEvent *aevent;
263         xDamageNotifyEvent *awire;
264         awire = (xDamageNotifyEvent *) wire;
265         aevent = (XDamageNotifyEvent *) event;
266         awire->type = aevent->type | (aevent->send_event ? 0x80 : 0);
267         awire->drawable = aevent->drawable;
268         awire->damage = aevent->damage;
269         awire->level = aevent->level | (aevent->more ? DamageNotifyMore : 0);
270         awire->timestamp = aevent->timestamp;
271         awire->area.x = aevent->area.x;
272         awire->area.y = aevent->area.y;
273         awire->area.width = aevent->area.width;
274         awire->area.height = aevent->area.height;
275         awire->geometry.x = aevent->geometry.x;
276         awire->geometry.y = aevent->geometry.y;
277         awire->geometry.width = aevent->geometry.width;
278         awire->geometry.height = aevent->geometry.height;
279         return True;
280     }
281     }
282     return False;
283 }
284
285 Bool 
286 XDamageQueryExtension (Display *dpy,
287                         int *event_base_return,
288                         int *error_base_return)
289 {
290     XDamageExtDisplayInfo *info = XDamageFindDisplay (dpy);
291
292     if (XDamageHasExtension(info)) 
293     {
294         *event_base_return = info->codes->first_event;
295         *error_base_return = info->codes->first_error;
296         return True;
297     } 
298     else
299         return False;
300 }
301
302 Status 
303 XDamageQueryVersion (Display *dpy,
304                     int     *major_version_return,
305                     int     *minor_version_return)
306 {
307     XDamageExtDisplayInfo       *info = XDamageFindDisplay (dpy);
308
309     XDamageCheckExtension (dpy, info, 0);
310
311     *major_version_return = info->major_version;
312     *minor_version_return = info->minor_version;
313     return 1;
314 }
315
316 Damage
317 XDamageCreate (Display *dpy, Drawable drawable, int level)
318 {
319     XDamageExtDisplayInfo       *info = XDamageFindDisplay (dpy);
320     xDamageCreateReq            *req;
321     Damage                      damage;
322
323     XDamageCheckExtension (dpy, info, 0);
324     LockDisplay (dpy);
325     GetReq (DamageCreate, req);
326     req->reqType = info->codes->major_opcode;
327     req->damageReqType = X_DamageCreate;
328     req->damage = damage = XAllocID (dpy);
329     req->drawable = drawable;
330     req->level = level;
331     UnlockDisplay (dpy);
332     SyncHandle ();
333     return damage;
334 }
335
336 void
337 XDamageDestroy (Display *dpy, Damage damage)
338 {
339     XDamageExtDisplayInfo       *info = XDamageFindDisplay (dpy);
340     xDamageDestroyReq           *req;
341
342     XDamageSimpleCheckExtension (dpy, info);
343     LockDisplay (dpy);
344     GetReq (DamageDestroy, req);
345     req->reqType = info->codes->major_opcode;
346     req->damageReqType = X_DamageDestroy;
347     req->damage = damage;
348     UnlockDisplay (dpy);
349     SyncHandle ();
350 }
351
352 void
353 XDamageSubtract (Display *dpy, Damage damage, 
354                  XserverRegion repair, XserverRegion parts)
355 {
356     XDamageExtDisplayInfo       *info = XDamageFindDisplay (dpy);
357     xDamageSubtractReq          *req;
358
359     XDamageSimpleCheckExtension (dpy, info);
360     LockDisplay (dpy);
361     GetReq (DamageSubtract, req);
362     req->reqType = info->codes->major_opcode;
363     req->damageReqType = X_DamageSubtract;
364     req->damage = damage;
365     req->repair = repair;
366     req->parts = parts;
367     UnlockDisplay (dpy);
368     SyncHandle ();
369 }
370
371 void
372 XDamageAdd (Display *dpy, Drawable drawable, XserverRegion region)
373 {
374     XDamageExtDisplayInfo       *info = XDamageFindDisplay (dpy);
375     xDamageAddReq               *req;
376
377     XDamageSimpleCheckExtension (dpy, info);
378     LockDisplay (dpy);
379     GetReq (DamageAdd, req);
380     req->reqType = info->codes->major_opcode;
381     req->damageReqType = X_DamageAdd;
382     req->drawable = drawable;
383     req->region = region;
384
385     UnlockDisplay (dpy);
386     SyncHandle ();
387 }