1 /*
2 * Copyright © 2003 Keith Packard
3 * Copyright © 2007 Eric Anholt
4 *
5 * Permission to use, copy, modify, distribute, and sell this software and its
6 * documentation for any purpose is hereby granted without fee, provided that
7 * the above copyright notice appear in all copies and that both that
8 * copyright notice and this permission notice appear in supporting
9 * documentation, and that the name of Keith Packard not be used in
10 * advertising or publicity pertaining to distribution of the software without
11 * specific, written prior permission. Keith Packard makes no
12 * representations about the suitability of this software for any purpose. It
13 * is provided "as is" without express or implied warranty.
14 *
15 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
17 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
19 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
20 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
21 * PERFORMANCE OF THIS SOFTWARE.
22 */
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27 #include "xdamageint.h"
28
29 XDamageExtInfo XDamageExtensionInfo;
30
31 const char XDamageExtensionName[] = DAMAGE_NAME;
32
33 static int
34 XDamageCloseDisplay (Display *dpy, XExtCodes *codes);
35
36 static Bool
37 XDamageWireToEvent(Display *dpy, XEvent *event, xEvent *wire);
38
39 static Status
40 XDamageEventToWire(Display *dpy, XEvent *event, xEvent *wire);
41
42 /*
43 * XDamageExtAddDisplay - add a display to this extension. (Replaces
44 * XextAddDisplay)
45 */
46 static XDamageExtDisplayInfo *
XDamageExtAddDisplay(XDamageExtInfo * extinfo,Display * dpy,const char * ext_name)47 XDamageExtAddDisplay (XDamageExtInfo *extinfo,
48 Display *dpy,
49 const char *ext_name)
50 {
51 XDamageExtDisplayInfo *info;
52 int ev;
53
54 info = (XDamageExtDisplayInfo *) Xmalloc (sizeof (XDamageExtDisplayInfo));
55 if (!info) return NULL;
56 info->display = dpy;
57
58 info->codes = XInitExtension (dpy, ext_name);
59
60 /*
61 * if the server has the extension, then we can initialize the
62 * appropriate function vectors
63 */
64 if (info->codes) {
65 xDamageQueryVersionReply rep;
66 xDamageQueryVersionReq *req;
67 XESetCloseDisplay (dpy, info->codes->extension,
68 XDamageCloseDisplay);
69 for (ev = info->codes->first_event;
70 ev < info->codes->first_event + XDamageNumberEvents;
71 ev++)
72 {
73 XESetWireToEvent (dpy, ev, XDamageWireToEvent);
74 XESetEventToWire (dpy, ev, XDamageEventToWire);
75 }
76 /*
77 * Get the version info
78 */
79 LockDisplay (dpy);
80 GetReq (DamageQueryVersion, req);
81 req->reqType = info->codes->major_opcode;
82 req->damageReqType = X_DamageQueryVersion;
83 req->majorVersion = DAMAGE_MAJOR;
84 req->minorVersion = DAMAGE_MINOR;
85 if (!_XReply (dpy, (xReply *) &rep, 0, xTrue))
86 {
87 UnlockDisplay (dpy);
88 SyncHandle ();
89 Xfree(info);
90 return NULL;
91 }
92 info->major_version = rep.majorVersion;
93 info->minor_version = rep.minorVersion;
94 UnlockDisplay (dpy);
95 SyncHandle ();
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
XDamageExtRemoveDisplay(XDamageExtInfo * extinfo,Display * dpy)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 *
XDamageExtFindDisplay(XDamageExtInfo * extinfo,Display * dpy)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 *
XDamageFindDisplay(Display * dpy)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
XDamageCloseDisplay(Display * dpy,XExtCodes * codes)208 XDamageCloseDisplay (Display *dpy, XExtCodes *codes)
209 {
210 return XDamageExtRemoveDisplay (&XDamageExtensionInfo, dpy);
211 }
212
213 static Bool
XDamageWireToEvent(Display * dpy,XEvent * event,xEvent * wire)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 & ~DamageNotifyMore;
234 aevent->more = (awire->level & DamageNotifyMore) ? True : False;
235 aevent->timestamp = awire->timestamp;
236 aevent->area.x = awire->area.x;
237 aevent->area.y = awire->area.y;
238 aevent->area.width = awire->area.width;
239 aevent->area.height = awire->area.height;
240 aevent->geometry.x = awire->geometry.x;
241 aevent->geometry.y = awire->geometry.y;
242 aevent->geometry.width = awire->geometry.width;
243 aevent->geometry.height = awire->geometry.height;
244 return True;
245 }
246 }
247 return False;
248 }
249
250 static Status
XDamageEventToWire(Display * dpy,XEvent * event,xEvent * wire)251 XDamageEventToWire(Display *dpy, XEvent *event, xEvent *wire)
252 {
253 XDamageExtDisplayInfo *info = XDamageFindDisplay(dpy);
254
255 XDamageCheckExtension(dpy, info, False);
256
257 switch ((event->type & 0x7F) - info->codes->first_event)
258 {
259 case XDamageNotify: {
260 XDamageNotifyEvent *aevent;
261 xDamageNotifyEvent *awire;
262 awire = (xDamageNotifyEvent *) wire;
263 aevent = (XDamageNotifyEvent *) event;
264 awire->type = aevent->type | (aevent->send_event ? 0x80 : 0);
265 awire->drawable = aevent->drawable;
266 awire->damage = aevent->damage;
267 awire->level = aevent->level | (aevent->more ? DamageNotifyMore : 0);
268 awire->timestamp = aevent->timestamp;
269 awire->area.x = aevent->area.x;
270 awire->area.y = aevent->area.y;
271 awire->area.width = aevent->area.width;
272 awire->area.height = aevent->area.height;
273 awire->geometry.x = aevent->geometry.x;
274 awire->geometry.y = aevent->geometry.y;
275 awire->geometry.width = aevent->geometry.width;
276 awire->geometry.height = aevent->geometry.height;
277 return True;
278 }
279 }
280 return False;
281 }
282
283 Bool
XDamageQueryExtension(Display * dpy,int * event_base_return,int * error_base_return)284 XDamageQueryExtension (Display *dpy,
285 int *event_base_return,
286 int *error_base_return)
287 {
288 XDamageExtDisplayInfo *info = XDamageFindDisplay (dpy);
289
290 if (XDamageHasExtension(info))
291 {
292 *event_base_return = info->codes->first_event;
293 *error_base_return = info->codes->first_error;
294 return True;
295 }
296 else
297 return False;
298 }
299
300 Status
XDamageQueryVersion(Display * dpy,int * major_version_return,int * minor_version_return)301 XDamageQueryVersion (Display *dpy,
302 int *major_version_return,
303 int *minor_version_return)
304 {
305 XDamageExtDisplayInfo *info = XDamageFindDisplay (dpy);
306
307 XDamageCheckExtension (dpy, info, 0);
308
309 *major_version_return = info->major_version;
310 *minor_version_return = info->minor_version;
311 return 1;
312 }
313
314 Damage
XDamageCreate(Display * dpy,Drawable drawable,int level)315 XDamageCreate (Display *dpy, Drawable drawable, int level)
316 {
317 XDamageExtDisplayInfo *info = XDamageFindDisplay (dpy);
318 xDamageCreateReq *req;
319 Damage damage;
320
321 XDamageCheckExtension (dpy, info, 0);
322 LockDisplay (dpy);
323 GetReq (DamageCreate, req);
324 req->reqType = info->codes->major_opcode;
325 req->damageReqType = X_DamageCreate;
326 req->damage = damage = XAllocID (dpy);
327 req->drawable = drawable;
328 req->level = level;
329 UnlockDisplay (dpy);
330 SyncHandle ();
331 return damage;
332 }
333
334 void
XDamageDestroy(Display * dpy,Damage damage)335 XDamageDestroy (Display *dpy, Damage damage)
336 {
337 XDamageExtDisplayInfo *info = XDamageFindDisplay (dpy);
338 xDamageDestroyReq *req;
339
340 XDamageSimpleCheckExtension (dpy, info);
341 LockDisplay (dpy);
342 GetReq (DamageDestroy, req);
343 req->reqType = info->codes->major_opcode;
344 req->damageReqType = X_DamageDestroy;
345 req->damage = damage;
346 UnlockDisplay (dpy);
347 SyncHandle ();
348 }
349
350 void
XDamageSubtract(Display * dpy,Damage damage,XserverRegion repair,XserverRegion parts)351 XDamageSubtract (Display *dpy, Damage damage,
352 XserverRegion repair, XserverRegion parts)
353 {
354 XDamageExtDisplayInfo *info = XDamageFindDisplay (dpy);
355 xDamageSubtractReq *req;
356
357 XDamageSimpleCheckExtension (dpy, info);
358 LockDisplay (dpy);
359 GetReq (DamageSubtract, req);
360 req->reqType = info->codes->major_opcode;
361 req->damageReqType = X_DamageSubtract;
362 req->damage = damage;
363 req->repair = repair;
364 req->parts = parts;
365 UnlockDisplay (dpy);
366 SyncHandle ();
367 }
368
369 void
XDamageAdd(Display * dpy,Drawable drawable,XserverRegion region)370 XDamageAdd (Display *dpy, Drawable drawable, XserverRegion region)
371 {
372 XDamageExtDisplayInfo *info = XDamageFindDisplay (dpy);
373 xDamageAddReq *req;
374
375 XDamageSimpleCheckExtension (dpy, info);
376 LockDisplay (dpy);
377 GetReq (DamageAdd, req);
378 req->reqType = info->codes->major_opcode;
379 req->damageReqType = X_DamageAdd;
380 req->drawable = drawable;
381 req->region = region;
382
383 UnlockDisplay (dpy);
384 SyncHandle ();
385 }
386