damageext.c revision 35c4bbdf
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
37typedef struct {
38    DamageExtPtr ext;
39    DamagePtr damage[MAXSCREENS];
40} PanoramiXDamageRes;
41
42static RESTYPE XRT_DAMAGE;
43static int (*PanoramiXSaveDamageCreate) (ClientPtr);
44
45#endif
46
47static unsigned char DamageReqCode;
48static int DamageEventBase;
49static RESTYPE DamageExtType;
50
51static DevPrivateKeyRec DamageClientPrivateKeyRec;
52
53#define DamageClientPrivateKey (&DamageClientPrivateKeyRec)
54
55static void
56DamageNoteCritical(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
67static void
68damageGetGeometry(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
90static void
91DamageExtNotify(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
135static void
136DamageExtReport(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
157static void
158DamageExtDestroy(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
167void
168DamageExtSetCritical(ClientPtr pClient, Bool critical)
169{
170    DamageClientPtr pDamageClient = GetDamageClient(pClient);
171
172    if (pDamageClient)
173        pDamageClient->critical += critical ? 1 : -1;
174}
175
176static int
177ProcDamageQueryVersion(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
214static void
215DamageExtRegister(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
228static DamageExtPtr
229DamageExtCreate(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
257static DamageExtPtr
258doDamageCreate(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
298static int
299ProcDamageCreate(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
309static int
310ProcDamageDestroy(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
322static RegionPtr
323DamageExtSubtractWindowClip(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
358out:
359    RegionDestroy(ret);
360    return NULL;
361}
362
363static void
364DamageExtFreeWindowClip(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 */
375static Bool
376DamageExtSubtract(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
403static int
404ProcDamageSubtract(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
436static int
437ProcDamageAdd(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 */
462static const int version_requests[] = {
463    X_DamageQueryVersion,       /* before client sends QueryVersion */
464    X_DamageAdd,                /* Version 1 */
465};
466
467#define NUM_VERSION_REQUESTS	(sizeof (version_requests) / sizeof (version_requests[0]))
468
469static int (*ProcDamageVector[XDamageNumberRequests]) (ClientPtr) = {
470    /*************** Version 1 ******************/
471    ProcDamageQueryVersion,
472    ProcDamageCreate,
473    ProcDamageDestroy,
474    ProcDamageSubtract,
475    /*************** Version 1.1 ****************/
476    ProcDamageAdd,
477};
478
479static int
480ProcDamageDispatch(ClientPtr client)
481{
482    REQUEST(xDamageReq);
483    DamageClientPtr pDamageClient = GetDamageClient(client);
484
485    if (pDamageClient->major_version >= NUM_VERSION_REQUESTS)
486        return BadRequest;
487    if (stuff->damageReqType > version_requests[pDamageClient->major_version])
488        return BadRequest;
489    return (*ProcDamageVector[stuff->damageReqType]) (client);
490}
491
492static int
493SProcDamageQueryVersion(ClientPtr client)
494{
495    REQUEST(xDamageQueryVersionReq);
496
497    swaps(&stuff->length);
498    REQUEST_SIZE_MATCH(xDamageQueryVersionReq);
499    swapl(&stuff->majorVersion);
500    swapl(&stuff->minorVersion);
501    return (*ProcDamageVector[stuff->damageReqType]) (client);
502}
503
504static int
505SProcDamageCreate(ClientPtr client)
506{
507    REQUEST(xDamageCreateReq);
508
509    swaps(&stuff->length);
510    REQUEST_SIZE_MATCH(xDamageCreateReq);
511    swapl(&stuff->damage);
512    swapl(&stuff->drawable);
513    return (*ProcDamageVector[stuff->damageReqType]) (client);
514}
515
516static int
517SProcDamageDestroy(ClientPtr client)
518{
519    REQUEST(xDamageDestroyReq);
520
521    swaps(&stuff->length);
522    REQUEST_SIZE_MATCH(xDamageDestroyReq);
523    swapl(&stuff->damage);
524    return (*ProcDamageVector[stuff->damageReqType]) (client);
525}
526
527static int
528SProcDamageSubtract(ClientPtr client)
529{
530    REQUEST(xDamageSubtractReq);
531
532    swaps(&stuff->length);
533    REQUEST_SIZE_MATCH(xDamageSubtractReq);
534    swapl(&stuff->damage);
535    swapl(&stuff->repair);
536    swapl(&stuff->parts);
537    return (*ProcDamageVector[stuff->damageReqType]) (client);
538}
539
540static int
541SProcDamageAdd(ClientPtr client)
542{
543    REQUEST(xDamageAddReq);
544
545    swaps(&stuff->length);
546    REQUEST_SIZE_MATCH(xDamageSubtractReq);
547    swapl(&stuff->drawable);
548    swapl(&stuff->region);
549    return (*ProcDamageVector[stuff->damageReqType]) (client);
550}
551
552static int (*SProcDamageVector[XDamageNumberRequests]) (ClientPtr) = {
553    /*************** Version 1 ******************/
554    SProcDamageQueryVersion,
555    SProcDamageCreate,
556    SProcDamageDestroy,
557    SProcDamageSubtract,
558    /*************** Version 1.1 ****************/
559    SProcDamageAdd,
560};
561
562static int
563SProcDamageDispatch(ClientPtr client)
564{
565    REQUEST(xDamageReq);
566    if (stuff->damageReqType >= XDamageNumberRequests)
567        return BadRequest;
568    return (*SProcDamageVector[stuff->damageReqType]) (client);
569}
570
571static void
572DamageClientCallback(CallbackListPtr *list, void *closure, void *data)
573{
574    NewClientInfoRec *clientinfo = (NewClientInfoRec *) data;
575    ClientPtr pClient = clientinfo->client;
576    DamageClientPtr pDamageClient = GetDamageClient(pClient);
577
578    pDamageClient->critical = 0;
579    pDamageClient->major_version = 0;
580    pDamageClient->minor_version = 0;
581}
582
583 /*ARGSUSED*/ static void
584DamageResetProc(ExtensionEntry * extEntry)
585{
586    DeleteCallback(&ClientStateCallback, DamageClientCallback, 0);
587}
588
589static int
590FreeDamageExt(void *value, XID did)
591{
592    DamageExtPtr pDamageExt = (DamageExtPtr) value;
593
594    /*
595     * Get rid of the resource table entry hanging from the window id
596     */
597    pDamageExt->id = 0;
598    if (pDamageExt->pDamage) {
599        DamageDestroy(pDamageExt->pDamage);
600    }
601    free(pDamageExt);
602    return Success;
603}
604
605static void
606SDamageNotifyEvent(xDamageNotifyEvent * from, xDamageNotifyEvent * to)
607{
608    to->type = from->type;
609    cpswaps(from->sequenceNumber, to->sequenceNumber);
610    cpswapl(from->drawable, to->drawable);
611    cpswapl(from->damage, to->damage);
612    cpswaps(from->area.x, to->area.x);
613    cpswaps(from->area.y, to->area.y);
614    cpswaps(from->area.width, to->area.width);
615    cpswaps(from->area.height, to->area.height);
616    cpswaps(from->geometry.x, to->geometry.x);
617    cpswaps(from->geometry.y, to->geometry.y);
618    cpswaps(from->geometry.width, to->geometry.width);
619    cpswaps(from->geometry.height, to->geometry.height);
620}
621
622#ifdef PANORAMIX
623
624static void
625PanoramiXDamageReport(DamagePtr pDamage, RegionPtr pRegion, void *closure)
626{
627    PanoramiXDamageRes *res = closure;
628    DamageExtPtr pDamageExt = res->ext;
629    WindowPtr pWin = (WindowPtr)pDamage->pDrawable;
630    ScreenPtr pScreen = pDamage->pScreen;
631
632    /* happens on unmap? sigh xinerama */
633    if (RegionNil(pRegion))
634        return;
635
636    /* translate root windows if necessary */
637    if (!pWin->parent)
638        RegionTranslate(pRegion, pScreen->x, pScreen->y);
639
640    /* add our damage to the protocol view */
641    DamageReportDamage(pDamageExt->pDamage, pRegion);
642
643    /* empty our view */
644    DamageEmpty(pDamage);
645}
646
647static void
648PanoramiXDamageExtDestroy(DamagePtr pDamage, void *closure)
649{
650    PanoramiXDamageRes *damage = closure;
651    damage->damage[pDamage->pScreen->myNum] = NULL;
652}
653
654static int
655PanoramiXDamageCreate(ClientPtr client)
656{
657    PanoramiXDamageRes *damage;
658    PanoramiXRes *draw;
659    int i, rc;
660
661    REQUEST(xDamageCreateReq);
662
663    REQUEST_SIZE_MATCH(xDamageCreateReq);
664    LEGAL_NEW_RESOURCE(stuff->damage, client);
665    rc = dixLookupResourceByClass((void **)&draw, stuff->drawable, XRC_DRAWABLE,
666                                  client, DixGetAttrAccess | DixReadAccess);
667    if (rc != Success)
668        return rc;
669
670    if (!(damage = calloc(1, sizeof(PanoramiXDamageRes))))
671        return BadAlloc;
672
673    if (!AddResource(stuff->damage, XRT_DAMAGE, damage))
674        return BadAlloc;
675
676    damage->ext = doDamageCreate(client, &rc);
677    if (rc == Success && draw->type == XRT_WINDOW) {
678        FOR_NSCREENS_FORWARD(i) {
679            DrawablePtr pDrawable;
680            DamagePtr pDamage = DamageCreate(PanoramiXDamageReport,
681                                             PanoramiXDamageExtDestroy,
682                                             DamageReportRawRegion,
683                                             FALSE,
684                                             screenInfo.screens[i],
685                                             damage);
686            if (!pDamage) {
687                rc = BadAlloc;
688            } else {
689                damage->damage[i] = pDamage;
690                rc = dixLookupDrawable(&pDrawable, draw->info[i].id, client,
691                                       M_WINDOW,
692                                       DixGetAttrAccess | DixReadAccess);
693            }
694            if (rc != Success)
695                break;
696
697            DamageExtRegister(pDrawable, pDamage, i != 0);
698        }
699    }
700
701    if (rc != Success)
702        FreeResource(stuff->damage, RT_NONE);
703
704    return rc;
705}
706
707static int
708PanoramiXDamageDelete(void *res, XID id)
709{
710    int i;
711    PanoramiXDamageRes *damage = res;
712
713    FOR_NSCREENS_BACKWARD(i) {
714        if (damage->damage[i]) {
715            DamageDestroy(damage->damage[i]);
716            damage->damage[i] = NULL;
717        }
718    }
719
720    free(damage);
721    return 1;
722}
723
724void
725PanoramiXDamageInit(void)
726{
727    XRT_DAMAGE = CreateNewResourceType(PanoramiXDamageDelete, "XineramaDamage");
728    if (!XRT_DAMAGE)
729        FatalError("Couldn't Xineramify Damage extension\n");
730
731    PanoramiXSaveDamageCreate = ProcDamageVector[X_DamageCreate];
732    ProcDamageVector[X_DamageCreate] = PanoramiXDamageCreate;
733}
734
735void
736PanoramiXDamageReset(void)
737{
738    ProcDamageVector[X_DamageCreate] = PanoramiXSaveDamageCreate;
739}
740
741#endif /* PANORAMIX */
742
743void
744DamageExtensionInit(void)
745{
746    ExtensionEntry *extEntry;
747    int s;
748
749    for (s = 0; s < screenInfo.numScreens; s++)
750        DamageSetup(screenInfo.screens[s]);
751
752    DamageExtType = CreateNewResourceType(FreeDamageExt, "DamageExt");
753    if (!DamageExtType)
754        return;
755
756    if (!dixRegisterPrivateKey
757        (&DamageClientPrivateKeyRec, PRIVATE_CLIENT, sizeof(DamageClientRec)))
758        return;
759
760    if (!AddCallback(&ClientStateCallback, DamageClientCallback, 0))
761        return;
762
763    if ((extEntry = AddExtension(DAMAGE_NAME, XDamageNumberEvents,
764                                 XDamageNumberErrors,
765                                 ProcDamageDispatch, SProcDamageDispatch,
766                                 DamageResetProc, StandardMinorOpcode)) != 0) {
767        DamageReqCode = (unsigned char) extEntry->base;
768        DamageEventBase = extEntry->eventBase;
769        EventSwapVector[DamageEventBase + XDamageNotify] =
770            (EventSwapPtr) SDamageNotifyEvent;
771        SetResourceTypeErrorValue(DamageExtType,
772                                  extEntry->errorBase + BadDamage);
773#ifdef PANORAMIX
774        if (XRT_DAMAGE)
775            SetResourceTypeErrorValue(XRT_DAMAGE,
776                                      extEntry->errorBase + BadDamage);
777#endif
778    }
779}
780