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
467static int (*ProcDamageVector[XDamageNumberRequests]) (ClientPtr) = {
468    /*************** Version 1 ******************/
469    ProcDamageQueryVersion,
470    ProcDamageCreate,
471    ProcDamageDestroy,
472    ProcDamageSubtract,
473    /*************** Version 1.1 ****************/
474    ProcDamageAdd,
475};
476
477static int
478ProcDamageDispatch(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
490static int _X_COLD
491SProcDamageQueryVersion(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
502static int _X_COLD
503SProcDamageCreate(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
514static int _X_COLD
515SProcDamageDestroy(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
525static int _X_COLD
526SProcDamageSubtract(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
538static int _X_COLD
539SProcDamageAdd(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
550static int (*SProcDamageVector[XDamageNumberRequests]) (ClientPtr) = {
551    /*************** Version 1 ******************/
552    SProcDamageQueryVersion,
553    SProcDamageCreate,
554    SProcDamageDestroy,
555    SProcDamageSubtract,
556    /*************** Version 1.1 ****************/
557    SProcDamageAdd,
558};
559
560static int _X_COLD
561SProcDamageDispatch(ClientPtr client)
562{
563    REQUEST(xDamageReq);
564    DamageClientPtr pDamageClient = GetDamageClient(client);
565
566    if (pDamageClient->major_version >= ARRAY_SIZE(version_requests))
567        return BadRequest;
568    if (stuff->damageReqType > version_requests[pDamageClient->major_version])
569        return BadRequest;
570    return (*SProcDamageVector[stuff->damageReqType]) (client);
571}
572
573static int
574FreeDamageExt(void *value, XID did)
575{
576    DamageExtPtr pDamageExt = (DamageExtPtr) value;
577
578    /*
579     * Get rid of the resource table entry hanging from the window id
580     */
581    pDamageExt->id = 0;
582    if (pDamageExt->pDamage) {
583        DamageDestroy(pDamageExt->pDamage);
584    }
585    free(pDamageExt);
586    return Success;
587}
588
589static void _X_COLD
590SDamageNotifyEvent(xDamageNotifyEvent * from, xDamageNotifyEvent * to)
591{
592    to->type = from->type;
593    cpswaps(from->sequenceNumber, to->sequenceNumber);
594    cpswapl(from->drawable, to->drawable);
595    cpswapl(from->damage, to->damage);
596    cpswaps(from->area.x, to->area.x);
597    cpswaps(from->area.y, to->area.y);
598    cpswaps(from->area.width, to->area.width);
599    cpswaps(from->area.height, to->area.height);
600    cpswaps(from->geometry.x, to->geometry.x);
601    cpswaps(from->geometry.y, to->geometry.y);
602    cpswaps(from->geometry.width, to->geometry.width);
603    cpswaps(from->geometry.height, to->geometry.height);
604}
605
606#ifdef PANORAMIX
607
608static void
609PanoramiXDamageReport(DamagePtr pDamage, RegionPtr pRegion, void *closure)
610{
611    PanoramiXDamageRes *res = closure;
612    DamageExtPtr pDamageExt = res->ext;
613    WindowPtr pWin = (WindowPtr)pDamage->pDrawable;
614    ScreenPtr pScreen = pDamage->pScreen;
615
616    /* happens on unmap? sigh xinerama */
617    if (RegionNil(pRegion))
618        return;
619
620    /* translate root windows if necessary */
621    if (!pWin->parent)
622        RegionTranslate(pRegion, pScreen->x, pScreen->y);
623
624    /* add our damage to the protocol view */
625    DamageReportDamage(pDamageExt->pDamage, pRegion);
626
627    /* empty our view */
628    DamageEmpty(pDamage);
629}
630
631static void
632PanoramiXDamageExtDestroy(DamagePtr pDamage, void *closure)
633{
634    PanoramiXDamageRes *damage = closure;
635    damage->damage[pDamage->pScreen->myNum] = NULL;
636}
637
638static int
639PanoramiXDamageCreate(ClientPtr client)
640{
641    PanoramiXDamageRes *damage;
642    PanoramiXRes *draw;
643    int i, rc;
644
645    REQUEST(xDamageCreateReq);
646
647    REQUEST_SIZE_MATCH(xDamageCreateReq);
648    LEGAL_NEW_RESOURCE(stuff->damage, client);
649    rc = dixLookupResourceByClass((void **)&draw, stuff->drawable, XRC_DRAWABLE,
650                                  client, DixGetAttrAccess | DixReadAccess);
651    if (rc != Success)
652        return rc;
653
654    if (!(damage = calloc(1, sizeof(PanoramiXDamageRes))))
655        return BadAlloc;
656
657    if (!AddResource(stuff->damage, XRT_DAMAGE, damage))
658        return BadAlloc;
659
660    damage->ext = doDamageCreate(client, &rc);
661    if (rc == Success && draw->type == XRT_WINDOW) {
662        FOR_NSCREENS_FORWARD(i) {
663            DrawablePtr pDrawable;
664            DamagePtr pDamage = DamageCreate(PanoramiXDamageReport,
665                                             PanoramiXDamageExtDestroy,
666                                             DamageReportRawRegion,
667                                             FALSE,
668                                             screenInfo.screens[i],
669                                             damage);
670            if (!pDamage) {
671                rc = BadAlloc;
672            } else {
673                damage->damage[i] = pDamage;
674                rc = dixLookupDrawable(&pDrawable, draw->info[i].id, client,
675                                       M_WINDOW,
676                                       DixGetAttrAccess | DixReadAccess);
677            }
678            if (rc != Success)
679                break;
680
681            DamageExtRegister(pDrawable, pDamage, i != 0);
682        }
683    }
684
685    if (rc != Success)
686        FreeResource(stuff->damage, RT_NONE);
687
688    return rc;
689}
690
691static int
692PanoramiXDamageDelete(void *res, XID id)
693{
694    int i;
695    PanoramiXDamageRes *damage = res;
696
697    FOR_NSCREENS_BACKWARD(i) {
698        if (damage->damage[i]) {
699            DamageDestroy(damage->damage[i]);
700            damage->damage[i] = NULL;
701        }
702    }
703
704    free(damage);
705    return 1;
706}
707
708void
709PanoramiXDamageInit(void)
710{
711    XRT_DAMAGE = CreateNewResourceType(PanoramiXDamageDelete, "XineramaDamage");
712    if (!XRT_DAMAGE)
713        FatalError("Couldn't Xineramify Damage extension\n");
714
715    PanoramiXSaveDamageCreate = ProcDamageVector[X_DamageCreate];
716    ProcDamageVector[X_DamageCreate] = PanoramiXDamageCreate;
717}
718
719void
720PanoramiXDamageReset(void)
721{
722    ProcDamageVector[X_DamageCreate] = PanoramiXSaveDamageCreate;
723}
724
725#endif /* PANORAMIX */
726
727void
728DamageExtensionInit(void)
729{
730    ExtensionEntry *extEntry;
731    int s;
732
733    for (s = 0; s < screenInfo.numScreens; s++)
734        DamageSetup(screenInfo.screens[s]);
735
736    DamageExtType = CreateNewResourceType(FreeDamageExt, "DamageExt");
737    if (!DamageExtType)
738        return;
739
740    if (!dixRegisterPrivateKey
741        (&DamageClientPrivateKeyRec, PRIVATE_CLIENT, sizeof(DamageClientRec)))
742        return;
743
744    if ((extEntry = AddExtension(DAMAGE_NAME, XDamageNumberEvents,
745                                 XDamageNumberErrors,
746                                 ProcDamageDispatch, SProcDamageDispatch,
747                                 NULL, StandardMinorOpcode)) != 0) {
748        DamageReqCode = (unsigned char) extEntry->base;
749        DamageEventBase = extEntry->eventBase;
750        EventSwapVector[DamageEventBase + XDamageNotify] =
751            (EventSwapPtr) SDamageNotifyEvent;
752        SetResourceTypeErrorValue(DamageExtType,
753                                  extEntry->errorBase + BadDamage);
754#ifdef PANORAMIX
755        if (XRT_DAMAGE)
756            SetResourceTypeErrorValue(XRT_DAMAGE,
757                                      extEntry->errorBase + BadDamage);
758#endif
759    }
760}
761