1 /*
2  * Copyright © 2002 Keith Packard
3  * Copyright 2013 Red Hat, Inc.
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_DIX_CONFIG_H
25 #include <dix-config.h>
26 #endif
27 
28 #include "damageextint.h"
29 #include "damagestr.h"
30 #include "protocol-versions.h"
31 #include "extinit.h"
32 
33 #ifdef PANORAMIX
34 #include "panoramiX.h"
35 #include "panoramiXsrv.h"
36 
37 typedef struct {
38     DamageExtPtr ext;
39     DamagePtr damage[MAXSCREENS];
40 } PanoramiXDamageRes;
41 
42 static RESTYPE XRT_DAMAGE;
43 static int (*PanoramiXSaveDamageCreate) (ClientPtr);
44 
45 #endif
46 
47 static unsigned char DamageReqCode;
48 static int DamageEventBase;
49 static RESTYPE DamageExtType;
50 
51 static DevPrivateKeyRec DamageClientPrivateKeyRec;
52 
53 #define DamageClientPrivateKey (&DamageClientPrivateKeyRec)
54 
55 static void
DamageNoteCritical(ClientPtr pClient)56 DamageNoteCritical(ClientPtr pClient)
57 {
58     DamageClientPtr pDamageClient = GetDamageClient(pClient);
59 
60     /* Composite extension marks clients with manual Subwindows as critical */
61     if (pDamageClient->critical > 0) {
62         SetCriticalOutputPending();
63         pClient->smart_priority = SMART_MAX_PRIORITY;
64     }
65 }
66 
67 static void
damageGetGeometry(DrawablePtr draw,int * x,int * y,int * w,int * h)68 damageGetGeometry(DrawablePtr draw, int *x, int *y, int *w, int *h)
69 {
70 #ifdef PANORAMIX
71     if (!noPanoramiXExtension && draw->type == DRAWABLE_WINDOW) {
72         WindowPtr win = (WindowPtr)draw;
73 
74         if (!win->parent) {
75             *x = screenInfo.x;
76             *y = screenInfo.y;
77             *w = screenInfo.width;
78             *h = screenInfo.height;
79             return;
80         }
81     }
82 #endif
83 
84     *x = draw->x;
85     *y = draw->y;
86     *w = draw->width;
87     *h = draw->height;
88 }
89 
90 static void
DamageExtNotify(DamageExtPtr pDamageExt,BoxPtr pBoxes,int nBoxes)91 DamageExtNotify(DamageExtPtr pDamageExt, BoxPtr pBoxes, int nBoxes)
92 {
93     ClientPtr pClient = pDamageExt->pClient;
94     DrawablePtr pDrawable = pDamageExt->pDrawable;
95     xDamageNotifyEvent ev;
96     int i, x, y, w, h;
97 
98     damageGetGeometry(pDrawable, &x, &y, &w, &h);
99 
100     UpdateCurrentTimeIf();
101     ev = (xDamageNotifyEvent) {
102         .type = DamageEventBase + XDamageNotify,
103         .level = pDamageExt->level,
104         .drawable = pDamageExt->drawable,
105         .damage = pDamageExt->id,
106         .timestamp = currentTime.milliseconds,
107         .geometry.x = x,
108         .geometry.y = y,
109         .geometry.width = w,
110         .geometry.height = h
111     };
112     if (pBoxes) {
113         for (i = 0; i < nBoxes; i++) {
114             ev.level = pDamageExt->level;
115             if (i < nBoxes - 1)
116                 ev.level |= DamageNotifyMore;
117             ev.area.x = pBoxes[i].x1;
118             ev.area.y = pBoxes[i].y1;
119             ev.area.width = pBoxes[i].x2 - pBoxes[i].x1;
120             ev.area.height = pBoxes[i].y2 - pBoxes[i].y1;
121             WriteEventsToClient(pClient, 1, (xEvent *) &ev);
122         }
123     }
124     else {
125         ev.area.x = 0;
126         ev.area.y = 0;
127         ev.area.width = w;
128         ev.area.height = h;
129         WriteEventsToClient(pClient, 1, (xEvent *) &ev);
130     }
131 
132     DamageNoteCritical(pClient);
133 }
134 
135 static void
DamageExtReport(DamagePtr pDamage,RegionPtr pRegion,void * closure)136 DamageExtReport(DamagePtr pDamage, RegionPtr pRegion, void *closure)
137 {
138     DamageExtPtr pDamageExt = closure;
139 
140     switch (pDamageExt->level) {
141     case DamageReportRawRegion:
142     case DamageReportDeltaRegion:
143         DamageExtNotify(pDamageExt, RegionRects(pRegion),
144                         RegionNumRects(pRegion));
145         break;
146     case DamageReportBoundingBox:
147         DamageExtNotify(pDamageExt, RegionExtents(pRegion), 1);
148         break;
149     case DamageReportNonEmpty:
150         DamageExtNotify(pDamageExt, NullBox, 0);
151         break;
152     case DamageReportNone:
153         break;
154     }
155 }
156 
157 static void
DamageExtDestroy(DamagePtr pDamage,void * closure)158 DamageExtDestroy(DamagePtr pDamage, void *closure)
159 {
160     DamageExtPtr pDamageExt = closure;
161 
162     pDamageExt->pDamage = 0;
163     if (pDamageExt->id)
164         FreeResource(pDamageExt->id, RT_NONE);
165 }
166 
167 void
DamageExtSetCritical(ClientPtr pClient,Bool critical)168 DamageExtSetCritical(ClientPtr pClient, Bool critical)
169 {
170     DamageClientPtr pDamageClient = GetDamageClient(pClient);
171 
172     if (pDamageClient)
173         pDamageClient->critical += critical ? 1 : -1;
174 }
175 
176 static int
ProcDamageQueryVersion(ClientPtr client)177 ProcDamageQueryVersion(ClientPtr client)
178 {
179     DamageClientPtr pDamageClient = GetDamageClient(client);
180     xDamageQueryVersionReply rep = {
181         .type = X_Reply,
182         .sequenceNumber = client->sequence,
183         .length = 0
184     };
185 
186     REQUEST(xDamageQueryVersionReq);
187 
188     REQUEST_SIZE_MATCH(xDamageQueryVersionReq);
189 
190     if (stuff->majorVersion < SERVER_DAMAGE_MAJOR_VERSION) {
191         rep.majorVersion = stuff->majorVersion;
192         rep.minorVersion = stuff->minorVersion;
193     }
194     else {
195         rep.majorVersion = SERVER_DAMAGE_MAJOR_VERSION;
196         if (stuff->majorVersion == SERVER_DAMAGE_MAJOR_VERSION &&
197             stuff->minorVersion < SERVER_DAMAGE_MINOR_VERSION)
198             rep.minorVersion = stuff->minorVersion;
199         else
200             rep.minorVersion = SERVER_DAMAGE_MINOR_VERSION;
201     }
202     pDamageClient->major_version = rep.majorVersion;
203     pDamageClient->minor_version = rep.minorVersion;
204     if (client->swapped) {
205         swaps(&rep.sequenceNumber);
206         swapl(&rep.length);
207         swapl(&rep.majorVersion);
208         swapl(&rep.minorVersion);
209     }
210     WriteToClient(client, sizeof(xDamageQueryVersionReply), &rep);
211     return Success;
212 }
213 
214 static void
DamageExtRegister(DrawablePtr pDrawable,DamagePtr pDamage,Bool report)215 DamageExtRegister(DrawablePtr pDrawable, DamagePtr pDamage, Bool report)
216 {
217     DamageSetReportAfterOp(pDamage, TRUE);
218     DamageRegister(pDrawable, pDamage);
219 
220     if (report) {
221         RegionPtr pRegion = &((WindowPtr) pDrawable)->borderClip;
222         RegionTranslate(pRegion, -pDrawable->x, -pDrawable->y);
223         DamageReportDamage(pDamage, pRegion);
224         RegionTranslate(pRegion, pDrawable->x, pDrawable->y);
225     }
226 }
227 
228 static DamageExtPtr
DamageExtCreate(DrawablePtr pDrawable,DamageReportLevel level,ClientPtr client,XID id,XID drawable)229 DamageExtCreate(DrawablePtr pDrawable, DamageReportLevel level,
230                 ClientPtr client, XID id, XID drawable)
231 {
232     DamageExtPtr pDamageExt = malloc(sizeof(DamageExtRec));
233     if (!pDamageExt)
234         return NULL;
235 
236     pDamageExt->id = id;
237     pDamageExt->drawable = drawable;
238     pDamageExt->pDrawable = pDrawable;
239     pDamageExt->level = level;
240     pDamageExt->pClient = client;
241     pDamageExt->pDamage = DamageCreate(DamageExtReport, DamageExtDestroy, level,
242                                        FALSE, pDrawable->pScreen, pDamageExt);
243     if (!pDamageExt->pDamage) {
244         free(pDamageExt);
245         return NULL;
246     }
247 
248     if (!AddResource(id, DamageExtType, (void *) pDamageExt))
249         return NULL;
250 
251     DamageExtRegister(pDrawable, pDamageExt->pDamage,
252                       pDrawable->type == DRAWABLE_WINDOW);
253 
254     return pDamageExt;
255 }
256 
257 static DamageExtPtr
doDamageCreate(ClientPtr client,int * rc)258 doDamageCreate(ClientPtr client, int *rc)
259 {
260     DrawablePtr pDrawable;
261     DamageExtPtr pDamageExt;
262     DamageReportLevel level;
263 
264     REQUEST(xDamageCreateReq);
265 
266     *rc = dixLookupDrawable(&pDrawable, stuff->drawable, client, 0,
267                             DixGetAttrAccess | DixReadAccess);
268     if (*rc != Success)
269         return NULL;
270 
271     switch (stuff->level) {
272     case XDamageReportRawRectangles:
273         level = DamageReportRawRegion;
274         break;
275     case XDamageReportDeltaRectangles:
276         level = DamageReportDeltaRegion;
277         break;
278     case XDamageReportBoundingBox:
279         level = DamageReportBoundingBox;
280         break;
281     case XDamageReportNonEmpty:
282         level = DamageReportNonEmpty;
283         break;
284     default:
285         client->errorValue = stuff->level;
286         *rc = BadValue;
287         return NULL;
288     }
289 
290     pDamageExt = DamageExtCreate(pDrawable, level, client, stuff->damage,
291                                  stuff->drawable);
292     if (!pDamageExt)
293         *rc = BadAlloc;
294 
295     return pDamageExt;
296 }
297 
298 static int
ProcDamageCreate(ClientPtr client)299 ProcDamageCreate(ClientPtr client)
300 {
301     int rc;
302     REQUEST(xDamageCreateReq);
303     REQUEST_SIZE_MATCH(xDamageCreateReq);
304     LEGAL_NEW_RESOURCE(stuff->damage, client);
305     doDamageCreate(client, &rc);
306     return rc;
307 }
308 
309 static int
ProcDamageDestroy(ClientPtr client)310 ProcDamageDestroy(ClientPtr client)
311 {
312     REQUEST(xDamageDestroyReq);
313     DamageExtPtr pDamageExt;
314 
315     REQUEST_SIZE_MATCH(xDamageDestroyReq);
316     VERIFY_DAMAGEEXT(pDamageExt, stuff->damage, client, DixWriteAccess);
317     FreeResource(stuff->damage, RT_NONE);
318     return Success;
319 }
320 
321 #ifdef PANORAMIX
322 static RegionPtr
DamageExtSubtractWindowClip(DamageExtPtr pDamageExt)323 DamageExtSubtractWindowClip(DamageExtPtr pDamageExt)
324 {
325     WindowPtr win = (WindowPtr)pDamageExt->pDrawable;
326     PanoramiXRes *res = NULL;
327     RegionPtr ret;
328     int i;
329 
330     if (!win->parent)
331         return &PanoramiXScreenRegion;
332 
333     dixLookupResourceByType((void **)&res, win->drawable.id, XRT_WINDOW,
334                             serverClient, DixReadAccess);
335     if (!res)
336         return NULL;
337 
338     ret = RegionCreate(NULL, 0);
339     if (!ret)
340         return NULL;
341 
342     FOR_NSCREENS_FORWARD(i) {
343         ScreenPtr screen;
344         if (Success != dixLookupWindow(&win, res->info[i].id, serverClient,
345                                        DixReadAccess))
346             goto out;
347 
348         screen = win->drawable.pScreen;
349 
350         RegionTranslate(ret, -screen->x, -screen->y);
351         if (!RegionUnion(ret, ret, &win->borderClip))
352             goto out;
353         RegionTranslate(ret, screen->x, screen->y);
354     }
355 
356     return ret;
357 
358 out:
359     RegionDestroy(ret);
360     return NULL;
361 }
362 
363 static void
DamageExtFreeWindowClip(RegionPtr reg)364 DamageExtFreeWindowClip(RegionPtr reg)
365 {
366     if (reg != &PanoramiXScreenRegion)
367         RegionDestroy(reg);
368 }
369 #endif
370 
371 /*
372  * DamageSubtract intersects with borderClip, so we must reconstruct the
373  * protocol's perspective of same...
374  */
375 static Bool
DamageExtSubtract(DamageExtPtr pDamageExt,const RegionPtr pRegion)376 DamageExtSubtract(DamageExtPtr pDamageExt, const RegionPtr pRegion)
377 {
378     DamagePtr pDamage = pDamageExt->pDamage;
379 
380 #ifdef PANORAMIX
381     if (!noPanoramiXExtension) {
382         RegionPtr damage = DamageRegion(pDamage);
383         RegionSubtract(damage, damage, pRegion);
384 
385         if (pDamageExt->pDrawable->type == DRAWABLE_WINDOW) {
386             DrawablePtr pDraw = pDamageExt->pDrawable;
387             RegionPtr clip = DamageExtSubtractWindowClip(pDamageExt);
388             if (clip) {
389                 RegionTranslate(clip, -pDraw->x, -pDraw->y);
390                 RegionIntersect(damage, damage, clip);
391                 RegionTranslate(clip, pDraw->x, pDraw->y);
392                 DamageExtFreeWindowClip(clip);
393             }
394         }
395 
396         return RegionNotEmpty(damage);
397     }
398 #endif
399 
400     return DamageSubtract(pDamage, pRegion);
401 }
402 
403 static int
ProcDamageSubtract(ClientPtr client)404 ProcDamageSubtract(ClientPtr client)
405 {
406     REQUEST(xDamageSubtractReq);
407     DamageExtPtr pDamageExt;
408     RegionPtr pRepair;
409     RegionPtr pParts;
410 
411     REQUEST_SIZE_MATCH(xDamageSubtractReq);
412     VERIFY_DAMAGEEXT(pDamageExt, stuff->damage, client, DixWriteAccess);
413     VERIFY_REGION_OR_NONE(pRepair, stuff->repair, client, DixWriteAccess);
414     VERIFY_REGION_OR_NONE(pParts, stuff->parts, client, DixWriteAccess);
415 
416     if (pDamageExt->level != DamageReportRawRegion) {
417         DamagePtr pDamage = pDamageExt->pDamage;
418 
419         if (pRepair) {
420             if (pParts)
421                 RegionIntersect(pParts, DamageRegion(pDamage), pRepair);
422             if (DamageExtSubtract(pDamageExt, pRepair))
423                 DamageExtReport(pDamage, DamageRegion(pDamage),
424                                 (void *) pDamageExt);
425         }
426         else {
427             if (pParts)
428                 RegionCopy(pParts, DamageRegion(pDamage));
429             DamageEmpty(pDamage);
430         }
431     }
432 
433     return Success;
434 }
435 
436 static int
ProcDamageAdd(ClientPtr client)437 ProcDamageAdd(ClientPtr client)
438 {
439     REQUEST(xDamageAddReq);
440     DrawablePtr pDrawable;
441     RegionPtr pRegion;
442     int rc;
443 
444     REQUEST_SIZE_MATCH(xDamageAddReq);
445     VERIFY_REGION(pRegion, stuff->region, client, DixWriteAccess);
446     rc = dixLookupDrawable(&pDrawable, stuff->drawable, client, 0,
447                            DixWriteAccess);
448     if (rc != Success)
449         return rc;
450 
451     /* The region is relative to the drawable origin, so translate it out to
452      * screen coordinates like damage expects.
453      */
454     RegionTranslate(pRegion, pDrawable->x, pDrawable->y);
455     DamageDamageRegion(pDrawable, pRegion);
456     RegionTranslate(pRegion, -pDrawable->x, -pDrawable->y);
457 
458     return Success;
459 }
460 
461 /* Major version controls available requests */
462 static const int version_requests[] = {
463     X_DamageQueryVersion,       /* before client sends QueryVersion */
464     X_DamageAdd,                /* Version 1 */
465 };
466 
467 static int (*ProcDamageVector[XDamageNumberRequests]) (ClientPtr) = {
468     /*************** Version 1 ******************/
469     ProcDamageQueryVersion,
470     ProcDamageCreate,
471     ProcDamageDestroy,
472     ProcDamageSubtract,
473     /*************** Version 1.1 ****************/
474     ProcDamageAdd,
475 };
476 
477 static int
ProcDamageDispatch(ClientPtr client)478 ProcDamageDispatch(ClientPtr client)
479 {
480     REQUEST(xDamageReq);
481     DamageClientPtr pDamageClient = GetDamageClient(client);
482 
483     if (pDamageClient->major_version >= ARRAY_SIZE(version_requests))
484         return BadRequest;
485     if (stuff->damageReqType > version_requests[pDamageClient->major_version])
486         return BadRequest;
487     return (*ProcDamageVector[stuff->damageReqType]) (client);
488 }
489 
490 static int _X_COLD
SProcDamageQueryVersion(ClientPtr client)491 SProcDamageQueryVersion(ClientPtr client)
492 {
493     REQUEST(xDamageQueryVersionReq);
494 
495     swaps(&stuff->length);
496     REQUEST_SIZE_MATCH(xDamageQueryVersionReq);
497     swapl(&stuff->majorVersion);
498     swapl(&stuff->minorVersion);
499     return (*ProcDamageVector[stuff->damageReqType]) (client);
500 }
501 
502 static int _X_COLD
SProcDamageCreate(ClientPtr client)503 SProcDamageCreate(ClientPtr client)
504 {
505     REQUEST(xDamageCreateReq);
506 
507     swaps(&stuff->length);
508     REQUEST_SIZE_MATCH(xDamageCreateReq);
509     swapl(&stuff->damage);
510     swapl(&stuff->drawable);
511     return (*ProcDamageVector[stuff->damageReqType]) (client);
512 }
513 
514 static int _X_COLD
SProcDamageDestroy(ClientPtr client)515 SProcDamageDestroy(ClientPtr client)
516 {
517     REQUEST(xDamageDestroyReq);
518 
519     swaps(&stuff->length);
520     REQUEST_SIZE_MATCH(xDamageDestroyReq);
521     swapl(&stuff->damage);
522     return (*ProcDamageVector[stuff->damageReqType]) (client);
523 }
524 
525 static int _X_COLD
SProcDamageSubtract(ClientPtr client)526 SProcDamageSubtract(ClientPtr client)
527 {
528     REQUEST(xDamageSubtractReq);
529 
530     swaps(&stuff->length);
531     REQUEST_SIZE_MATCH(xDamageSubtractReq);
532     swapl(&stuff->damage);
533     swapl(&stuff->repair);
534     swapl(&stuff->parts);
535     return (*ProcDamageVector[stuff->damageReqType]) (client);
536 }
537 
538 static int _X_COLD
SProcDamageAdd(ClientPtr client)539 SProcDamageAdd(ClientPtr client)
540 {
541     REQUEST(xDamageAddReq);
542 
543     swaps(&stuff->length);
544     REQUEST_SIZE_MATCH(xDamageSubtractReq);
545     swapl(&stuff->drawable);
546     swapl(&stuff->region);
547     return (*ProcDamageVector[stuff->damageReqType]) (client);
548 }
549 
550 static int (*SProcDamageVector[XDamageNumberRequests]) (ClientPtr) = {
551     /*************** Version 1 ******************/
552     SProcDamageQueryVersion,
553     SProcDamageCreate,
554     SProcDamageDestroy,
555     SProcDamageSubtract,
556     /*************** Version 1.1 ****************/
557     SProcDamageAdd,
558 };
559 
560 static int _X_COLD
SProcDamageDispatch(ClientPtr client)561 SProcDamageDispatch(ClientPtr client)
562 {
563     REQUEST(xDamageReq);
564     if (stuff->damageReqType >= XDamageNumberRequests)
565         return BadRequest;
566     return (*SProcDamageVector[stuff->damageReqType]) (client);
567 }
568 
569 static int
FreeDamageExt(void * value,XID did)570 FreeDamageExt(void *value, XID did)
571 {
572     DamageExtPtr pDamageExt = (DamageExtPtr) value;
573 
574     /*
575      * Get rid of the resource table entry hanging from the window id
576      */
577     pDamageExt->id = 0;
578     if (pDamageExt->pDamage) {
579         DamageDestroy(pDamageExt->pDamage);
580     }
581     free(pDamageExt);
582     return Success;
583 }
584 
585 static void _X_COLD
SDamageNotifyEvent(xDamageNotifyEvent * from,xDamageNotifyEvent * to)586 SDamageNotifyEvent(xDamageNotifyEvent * from, xDamageNotifyEvent * to)
587 {
588     to->type = from->type;
589     cpswaps(from->sequenceNumber, to->sequenceNumber);
590     cpswapl(from->drawable, to->drawable);
591     cpswapl(from->damage, to->damage);
592     cpswaps(from->area.x, to->area.x);
593     cpswaps(from->area.y, to->area.y);
594     cpswaps(from->area.width, to->area.width);
595     cpswaps(from->area.height, to->area.height);
596     cpswaps(from->geometry.x, to->geometry.x);
597     cpswaps(from->geometry.y, to->geometry.y);
598     cpswaps(from->geometry.width, to->geometry.width);
599     cpswaps(from->geometry.height, to->geometry.height);
600 }
601 
602 #ifdef PANORAMIX
603 
604 static void
PanoramiXDamageReport(DamagePtr pDamage,RegionPtr pRegion,void * closure)605 PanoramiXDamageReport(DamagePtr pDamage, RegionPtr pRegion, void *closure)
606 {
607     PanoramiXDamageRes *res = closure;
608     DamageExtPtr pDamageExt = res->ext;
609     WindowPtr pWin = (WindowPtr)pDamage->pDrawable;
610     ScreenPtr pScreen = pDamage->pScreen;
611 
612     /* happens on unmap? sigh xinerama */
613     if (RegionNil(pRegion))
614         return;
615 
616     /* translate root windows if necessary */
617     if (!pWin->parent)
618         RegionTranslate(pRegion, pScreen->x, pScreen->y);
619 
620     /* add our damage to the protocol view */
621     DamageReportDamage(pDamageExt->pDamage, pRegion);
622 
623     /* empty our view */
624     DamageEmpty(pDamage);
625 }
626 
627 static void
PanoramiXDamageExtDestroy(DamagePtr pDamage,void * closure)628 PanoramiXDamageExtDestroy(DamagePtr pDamage, void *closure)
629 {
630     PanoramiXDamageRes *damage = closure;
631     damage->damage[pDamage->pScreen->myNum] = NULL;
632 }
633 
634 static int
PanoramiXDamageCreate(ClientPtr client)635 PanoramiXDamageCreate(ClientPtr client)
636 {
637     PanoramiXDamageRes *damage;
638     PanoramiXRes *draw;
639     int i, rc;
640 
641     REQUEST(xDamageCreateReq);
642 
643     REQUEST_SIZE_MATCH(xDamageCreateReq);
644     LEGAL_NEW_RESOURCE(stuff->damage, client);
645     rc = dixLookupResourceByClass((void **)&draw, stuff->drawable, XRC_DRAWABLE,
646                                   client, DixGetAttrAccess | DixReadAccess);
647     if (rc != Success)
648         return rc;
649 
650     if (!(damage = calloc(1, sizeof(PanoramiXDamageRes))))
651         return BadAlloc;
652 
653     if (!AddResource(stuff->damage, XRT_DAMAGE, damage))
654         return BadAlloc;
655 
656     damage->ext = doDamageCreate(client, &rc);
657     if (rc == Success && draw->type == XRT_WINDOW) {
658         FOR_NSCREENS_FORWARD(i) {
659             DrawablePtr pDrawable;
660             DamagePtr pDamage = DamageCreate(PanoramiXDamageReport,
661                                              PanoramiXDamageExtDestroy,
662                                              DamageReportRawRegion,
663                                              FALSE,
664                                              screenInfo.screens[i],
665                                              damage);
666             if (!pDamage) {
667                 rc = BadAlloc;
668             } else {
669                 damage->damage[i] = pDamage;
670                 rc = dixLookupDrawable(&pDrawable, draw->info[i].id, client,
671                                        M_WINDOW,
672                                        DixGetAttrAccess | DixReadAccess);
673             }
674             if (rc != Success)
675                 break;
676 
677             DamageExtRegister(pDrawable, pDamage, i != 0);
678         }
679     }
680 
681     if (rc != Success)
682         FreeResource(stuff->damage, RT_NONE);
683 
684     return rc;
685 }
686 
687 static int
PanoramiXDamageDelete(void * res,XID id)688 PanoramiXDamageDelete(void *res, XID id)
689 {
690     int i;
691     PanoramiXDamageRes *damage = res;
692 
693     FOR_NSCREENS_BACKWARD(i) {
694         if (damage->damage[i]) {
695             DamageDestroy(damage->damage[i]);
696             damage->damage[i] = NULL;
697         }
698     }
699 
700     free(damage);
701     return 1;
702 }
703 
704 void
PanoramiXDamageInit(void)705 PanoramiXDamageInit(void)
706 {
707     XRT_DAMAGE = CreateNewResourceType(PanoramiXDamageDelete, "XineramaDamage");
708     if (!XRT_DAMAGE)
709         FatalError("Couldn't Xineramify Damage extension\n");
710 
711     PanoramiXSaveDamageCreate = ProcDamageVector[X_DamageCreate];
712     ProcDamageVector[X_DamageCreate] = PanoramiXDamageCreate;
713 }
714 
715 void
PanoramiXDamageReset(void)716 PanoramiXDamageReset(void)
717 {
718     ProcDamageVector[X_DamageCreate] = PanoramiXSaveDamageCreate;
719 }
720 
721 #endif /* PANORAMIX */
722 
723 void
DamageExtensionInit(void)724 DamageExtensionInit(void)
725 {
726     ExtensionEntry *extEntry;
727     int s;
728 
729     for (s = 0; s < screenInfo.numScreens; s++)
730         DamageSetup(screenInfo.screens[s]);
731 
732     DamageExtType = CreateNewResourceType(FreeDamageExt, "DamageExt");
733     if (!DamageExtType)
734         return;
735 
736     if (!dixRegisterPrivateKey
737         (&DamageClientPrivateKeyRec, PRIVATE_CLIENT, sizeof(DamageClientRec)))
738         return;
739 
740     if ((extEntry = AddExtension(DAMAGE_NAME, XDamageNumberEvents,
741                                  XDamageNumberErrors,
742                                  ProcDamageDispatch, SProcDamageDispatch,
743                                  NULL, StandardMinorOpcode)) != 0) {
744         DamageReqCode = (unsigned char) extEntry->base;
745         DamageEventBase = extEntry->eventBase;
746         EventSwapVector[DamageEventBase + XDamageNotify] =
747             (EventSwapPtr) SDamageNotifyEvent;
748         SetResourceTypeErrorValue(DamageExtType,
749                                   extEntry->errorBase + BadDamage);
750 #ifdef PANORAMIX
751         if (XRT_DAMAGE)
752             SetResourceTypeErrorValue(XRT_DAMAGE,
753                                       extEntry->errorBase + BadDamage);
754 #endif
755     }
756 }
757