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