damageext.c revision 35c4bbdf
105b261ecSmrg/*
205b261ecSmrg * Copyright © 2002 Keith Packard
335c4bbdfSmrg * Copyright 2013 Red Hat, Inc.
405b261ecSmrg *
505b261ecSmrg * Permission to use, copy, modify, distribute, and sell this software and its
605b261ecSmrg * documentation for any purpose is hereby granted without fee, provided that
705b261ecSmrg * the above copyright notice appear in all copies and that both that
805b261ecSmrg * copyright notice and this permission notice appear in supporting
905b261ecSmrg * documentation, and that the name of Keith Packard not be used in
1005b261ecSmrg * advertising or publicity pertaining to distribution of the software without
1105b261ecSmrg * specific, written prior permission.  Keith Packard makes no
1205b261ecSmrg * representations about the suitability of this software for any purpose.  It
1305b261ecSmrg * is provided "as is" without express or implied warranty.
1405b261ecSmrg *
1505b261ecSmrg * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
1605b261ecSmrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
1705b261ecSmrg * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
1805b261ecSmrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
1905b261ecSmrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
2005b261ecSmrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
2105b261ecSmrg * PERFORMANCE OF THIS SOFTWARE.
2205b261ecSmrg */
2305b261ecSmrg
2405b261ecSmrg#ifdef HAVE_DIX_CONFIG_H
2505b261ecSmrg#include <dix-config.h>
2605b261ecSmrg#endif
2705b261ecSmrg
2805b261ecSmrg#include "damageextint.h"
2935c4bbdfSmrg#include "damagestr.h"
306747b715Smrg#include "protocol-versions.h"
3135c4bbdfSmrg#include "extinit.h"
3205b261ecSmrg
3335c4bbdfSmrg#ifdef PANORAMIX
3435c4bbdfSmrg#include "panoramiX.h"
3535c4bbdfSmrg#include "panoramiXsrv.h"
3635c4bbdfSmrg
3735c4bbdfSmrgtypedef struct {
3835c4bbdfSmrg    DamageExtPtr ext;
3935c4bbdfSmrg    DamagePtr damage[MAXSCREENS];
4035c4bbdfSmrg} PanoramiXDamageRes;
4135c4bbdfSmrg
4235c4bbdfSmrgstatic RESTYPE XRT_DAMAGE;
4335c4bbdfSmrgstatic int (*PanoramiXSaveDamageCreate) (ClientPtr);
4435c4bbdfSmrg
4535c4bbdfSmrg#endif
4635c4bbdfSmrg
4735c4bbdfSmrgstatic unsigned char DamageReqCode;
4835c4bbdfSmrgstatic int DamageEventBase;
4935c4bbdfSmrgstatic RESTYPE DamageExtType;
5005b261ecSmrg
516747b715Smrgstatic DevPrivateKeyRec DamageClientPrivateKeyRec;
5235c4bbdfSmrg
536747b715Smrg#define DamageClientPrivateKey (&DamageClientPrivateKeyRec)
5405b261ecSmrg
5505b261ecSmrgstatic void
5635c4bbdfSmrgDamageNoteCritical(ClientPtr pClient)
5735c4bbdfSmrg{
5835c4bbdfSmrg    DamageClientPtr pDamageClient = GetDamageClient(pClient);
5935c4bbdfSmrg
6035c4bbdfSmrg    /* Composite extension marks clients with manual Subwindows as critical */
6135c4bbdfSmrg    if (pDamageClient->critical > 0) {
6235c4bbdfSmrg        SetCriticalOutputPending();
6335c4bbdfSmrg        pClient->smart_priority = SMART_MAX_PRIORITY;
6405b261ecSmrg    }
6535c4bbdfSmrg}
6635c4bbdfSmrg
6735c4bbdfSmrgstatic void
6835c4bbdfSmrgdamageGetGeometry(DrawablePtr draw, int *x, int *y, int *w, int *h)
6935c4bbdfSmrg{
7035c4bbdfSmrg#ifdef PANORAMIX
7135c4bbdfSmrg    if (!noPanoramiXExtension && draw->type == DRAWABLE_WINDOW) {
7235c4bbdfSmrg        WindowPtr win = (WindowPtr)draw;
7335c4bbdfSmrg
7435c4bbdfSmrg        if (!win->parent) {
7535c4bbdfSmrg            *x = screenInfo.x;
7635c4bbdfSmrg            *y = screenInfo.y;
7735c4bbdfSmrg            *w = screenInfo.width;
7835c4bbdfSmrg            *h = screenInfo.height;
7935c4bbdfSmrg            return;
8035c4bbdfSmrg        }
8105b261ecSmrg    }
8235c4bbdfSmrg#endif
8335c4bbdfSmrg
8435c4bbdfSmrg    *x = draw->x;
8535c4bbdfSmrg    *y = draw->y;
8635c4bbdfSmrg    *w = draw->width;
8735c4bbdfSmrg    *h = draw->height;
8835c4bbdfSmrg}
8935c4bbdfSmrg
9035c4bbdfSmrgstatic void
9135c4bbdfSmrgDamageExtNotify(DamageExtPtr pDamageExt, BoxPtr pBoxes, int nBoxes)
9235c4bbdfSmrg{
9335c4bbdfSmrg    ClientPtr pClient = pDamageExt->pClient;
9435c4bbdfSmrg    DrawablePtr pDrawable = pDamageExt->pDrawable;
9535c4bbdfSmrg    xDamageNotifyEvent ev;
9635c4bbdfSmrg    int i, x, y, w, h;
9735c4bbdfSmrg
9835c4bbdfSmrg    damageGetGeometry(pDrawable, &x, &y, &w, &h);
9935c4bbdfSmrg
10035c4bbdfSmrg    UpdateCurrentTimeIf();
10135c4bbdfSmrg    ev = (xDamageNotifyEvent) {
10235c4bbdfSmrg        .type = DamageEventBase + XDamageNotify,
10335c4bbdfSmrg        .level = pDamageExt->level,
10435c4bbdfSmrg        .drawable = pDamageExt->drawable,
10535c4bbdfSmrg        .damage = pDamageExt->id,
10635c4bbdfSmrg        .timestamp = currentTime.milliseconds,
10735c4bbdfSmrg        .geometry.x = x,
10835c4bbdfSmrg        .geometry.y = y,
10935c4bbdfSmrg        .geometry.width = w,
11035c4bbdfSmrg        .geometry.height = h
11135c4bbdfSmrg    };
11235c4bbdfSmrg    if (pBoxes) {
11335c4bbdfSmrg        for (i = 0; i < nBoxes; i++) {
11435c4bbdfSmrg            ev.level = pDamageExt->level;
11535c4bbdfSmrg            if (i < nBoxes - 1)
11635c4bbdfSmrg                ev.level |= DamageNotifyMore;
11735c4bbdfSmrg            ev.area.x = pBoxes[i].x1;
11835c4bbdfSmrg            ev.area.y = pBoxes[i].y1;
11935c4bbdfSmrg            ev.area.width = pBoxes[i].x2 - pBoxes[i].x1;
12035c4bbdfSmrg            ev.area.height = pBoxes[i].y2 - pBoxes[i].y1;
12135c4bbdfSmrg            WriteEventsToClient(pClient, 1, (xEvent *) &ev);
12235c4bbdfSmrg        }
12305b261ecSmrg    }
12435c4bbdfSmrg    else {
12535c4bbdfSmrg        ev.area.x = 0;
12635c4bbdfSmrg        ev.area.y = 0;
12735c4bbdfSmrg        ev.area.width = w;
12835c4bbdfSmrg        ev.area.height = h;
12935c4bbdfSmrg        WriteEventsToClient(pClient, 1, (xEvent *) &ev);
13035c4bbdfSmrg    }
13135c4bbdfSmrg
13235c4bbdfSmrg    DamageNoteCritical(pClient);
13305b261ecSmrg}
13405b261ecSmrg
13505b261ecSmrgstatic void
13635c4bbdfSmrgDamageExtReport(DamagePtr pDamage, RegionPtr pRegion, void *closure)
13705b261ecSmrg{
13835c4bbdfSmrg    DamageExtPtr pDamageExt = closure;
13905b261ecSmrg
14005b261ecSmrg    switch (pDamageExt->level) {
14105b261ecSmrg    case DamageReportRawRegion:
14205b261ecSmrg    case DamageReportDeltaRegion:
14335c4bbdfSmrg        DamageExtNotify(pDamageExt, RegionRects(pRegion),
14435c4bbdfSmrg                        RegionNumRects(pRegion));
14535c4bbdfSmrg        break;
14605b261ecSmrg    case DamageReportBoundingBox:
14735c4bbdfSmrg        DamageExtNotify(pDamageExt, RegionExtents(pRegion), 1);
14835c4bbdfSmrg        break;
14905b261ecSmrg    case DamageReportNonEmpty:
15035c4bbdfSmrg        DamageExtNotify(pDamageExt, NullBox, 0);
15135c4bbdfSmrg        break;
15205b261ecSmrg    case DamageReportNone:
15335c4bbdfSmrg        break;
15405b261ecSmrg    }
15505b261ecSmrg}
15605b261ecSmrg
15705b261ecSmrgstatic void
15835c4bbdfSmrgDamageExtDestroy(DamagePtr pDamage, void *closure)
15905b261ecSmrg{
16035c4bbdfSmrg    DamageExtPtr pDamageExt = closure;
16135c4bbdfSmrg
16205b261ecSmrg    pDamageExt->pDamage = 0;
16305b261ecSmrg    if (pDamageExt->id)
16435c4bbdfSmrg        FreeResource(pDamageExt->id, RT_NONE);
16505b261ecSmrg}
16605b261ecSmrg
16705b261ecSmrgvoid
16835c4bbdfSmrgDamageExtSetCritical(ClientPtr pClient, Bool critical)
16905b261ecSmrg{
17035c4bbdfSmrg    DamageClientPtr pDamageClient = GetDamageClient(pClient);
17105b261ecSmrg
17205b261ecSmrg    if (pDamageClient)
17335c4bbdfSmrg        pDamageClient->critical += critical ? 1 : -1;
17405b261ecSmrg}
17505b261ecSmrg
17605b261ecSmrgstatic int
17705b261ecSmrgProcDamageQueryVersion(ClientPtr client)
17805b261ecSmrg{
17935c4bbdfSmrg    DamageClientPtr pDamageClient = GetDamageClient(client);
18035c4bbdfSmrg    xDamageQueryVersionReply rep = {
18135c4bbdfSmrg        .type = X_Reply,
18235c4bbdfSmrg        .sequenceNumber = client->sequence,
18335c4bbdfSmrg        .length = 0
18435c4bbdfSmrg    };
18535c4bbdfSmrg
18605b261ecSmrg    REQUEST(xDamageQueryVersionReq);
18705b261ecSmrg
18805b261ecSmrg    REQUEST_SIZE_MATCH(xDamageQueryVersionReq);
18935c4bbdfSmrg
1906747b715Smrg    if (stuff->majorVersion < SERVER_DAMAGE_MAJOR_VERSION) {
19135c4bbdfSmrg        rep.majorVersion = stuff->majorVersion;
19235c4bbdfSmrg        rep.minorVersion = stuff->minorVersion;
19335c4bbdfSmrg    }
19435c4bbdfSmrg    else {
19535c4bbdfSmrg        rep.majorVersion = SERVER_DAMAGE_MAJOR_VERSION;
19635c4bbdfSmrg        if (stuff->majorVersion == SERVER_DAMAGE_MAJOR_VERSION &&
19735c4bbdfSmrg            stuff->minorVersion < SERVER_DAMAGE_MINOR_VERSION)
19835c4bbdfSmrg            rep.minorVersion = stuff->minorVersion;
19935c4bbdfSmrg        else
20035c4bbdfSmrg            rep.minorVersion = SERVER_DAMAGE_MINOR_VERSION;
20105b261ecSmrg    }
20205b261ecSmrg    pDamageClient->major_version = rep.majorVersion;
20305b261ecSmrg    pDamageClient->minor_version = rep.minorVersion;
20405b261ecSmrg    if (client->swapped) {
20535c4bbdfSmrg        swaps(&rep.sequenceNumber);
20635c4bbdfSmrg        swapl(&rep.length);
20735c4bbdfSmrg        swapl(&rep.majorVersion);
20835c4bbdfSmrg        swapl(&rep.minorVersion);
20905b261ecSmrg    }
21035c4bbdfSmrg    WriteToClient(client, sizeof(xDamageQueryVersionReply), &rep);
2116747b715Smrg    return Success;
21205b261ecSmrg}
21305b261ecSmrg
21435c4bbdfSmrgstatic void
21535c4bbdfSmrgDamageExtRegister(DrawablePtr pDrawable, DamagePtr pDamage, Bool report)
21635c4bbdfSmrg{
21735c4bbdfSmrg    DamageSetReportAfterOp(pDamage, TRUE);
21835c4bbdfSmrg    DamageRegister(pDrawable, pDamage);
21935c4bbdfSmrg
22035c4bbdfSmrg    if (report) {
22135c4bbdfSmrg        RegionPtr pRegion = &((WindowPtr) pDrawable)->borderClip;
22235c4bbdfSmrg        RegionTranslate(pRegion, -pDrawable->x, -pDrawable->y);
22335c4bbdfSmrg        DamageReportDamage(pDamage, pRegion);
22435c4bbdfSmrg        RegionTranslate(pRegion, pDrawable->x, pDrawable->y);
22535c4bbdfSmrg    }
22635c4bbdfSmrg}
22735c4bbdfSmrg
22835c4bbdfSmrgstatic DamageExtPtr
22935c4bbdfSmrgDamageExtCreate(DrawablePtr pDrawable, DamageReportLevel level,
23035c4bbdfSmrg                ClientPtr client, XID id, XID drawable)
23135c4bbdfSmrg{
23235c4bbdfSmrg    DamageExtPtr pDamageExt = malloc(sizeof(DamageExtRec));
23335c4bbdfSmrg    if (!pDamageExt)
23435c4bbdfSmrg        return NULL;
23535c4bbdfSmrg
23635c4bbdfSmrg    pDamageExt->id = id;
23735c4bbdfSmrg    pDamageExt->drawable = drawable;
23835c4bbdfSmrg    pDamageExt->pDrawable = pDrawable;
23935c4bbdfSmrg    pDamageExt->level = level;
24035c4bbdfSmrg    pDamageExt->pClient = client;
24135c4bbdfSmrg    pDamageExt->pDamage = DamageCreate(DamageExtReport, DamageExtDestroy, level,
24235c4bbdfSmrg                                       FALSE, pDrawable->pScreen, pDamageExt);
24335c4bbdfSmrg    if (!pDamageExt->pDamage) {
24435c4bbdfSmrg        free(pDamageExt);
24535c4bbdfSmrg        return NULL;
24635c4bbdfSmrg    }
24735c4bbdfSmrg
24835c4bbdfSmrg    if (!AddResource(id, DamageExtType, (void *) pDamageExt))
24935c4bbdfSmrg        return NULL;
25035c4bbdfSmrg
25135c4bbdfSmrg    DamageExtRegister(pDrawable, pDamageExt->pDamage,
25235c4bbdfSmrg                      pDrawable->type == DRAWABLE_WINDOW);
25335c4bbdfSmrg
25435c4bbdfSmrg    return pDamageExt;
25535c4bbdfSmrg}
25635c4bbdfSmrg
25735c4bbdfSmrgstatic DamageExtPtr
25835c4bbdfSmrgdoDamageCreate(ClientPtr client, int *rc)
25935c4bbdfSmrg{
26035c4bbdfSmrg    DrawablePtr pDrawable;
26135c4bbdfSmrg    DamageExtPtr pDamageExt;
26235c4bbdfSmrg    DamageReportLevel level;
26335c4bbdfSmrg
26405b261ecSmrg    REQUEST(xDamageCreateReq);
26505b261ecSmrg
26635c4bbdfSmrg    *rc = dixLookupDrawable(&pDrawable, stuff->drawable, client, 0,
26735c4bbdfSmrg                            DixGetAttrAccess | DixReadAccess);
26835c4bbdfSmrg    if (*rc != Success)
26935c4bbdfSmrg        return NULL;
27005b261ecSmrg
27105b261ecSmrg    switch (stuff->level) {
27205b261ecSmrg    case XDamageReportRawRectangles:
27335c4bbdfSmrg        level = DamageReportRawRegion;
27435c4bbdfSmrg        break;
27505b261ecSmrg    case XDamageReportDeltaRectangles:
27635c4bbdfSmrg        level = DamageReportDeltaRegion;
27735c4bbdfSmrg        break;
27805b261ecSmrg    case XDamageReportBoundingBox:
27935c4bbdfSmrg        level = DamageReportBoundingBox;
28035c4bbdfSmrg        break;
28105b261ecSmrg    case XDamageReportNonEmpty:
28235c4bbdfSmrg        level = DamageReportNonEmpty;
28335c4bbdfSmrg        break;
28405b261ecSmrg    default:
28535c4bbdfSmrg        client->errorValue = stuff->level;
28635c4bbdfSmrg        *rc = BadValue;
28735c4bbdfSmrg        return NULL;
28805b261ecSmrg    }
28905b261ecSmrg
29035c4bbdfSmrg    pDamageExt = DamageExtCreate(pDrawable, level, client, stuff->damage,
29135c4bbdfSmrg                                 stuff->drawable);
29235c4bbdfSmrg    if (!pDamageExt)
29335c4bbdfSmrg        *rc = BadAlloc;
29405b261ecSmrg
29535c4bbdfSmrg    return pDamageExt;
29635c4bbdfSmrg}
29705b261ecSmrg
29835c4bbdfSmrgstatic int
29935c4bbdfSmrgProcDamageCreate(ClientPtr client)
30035c4bbdfSmrg{
30135c4bbdfSmrg    int rc;
30235c4bbdfSmrg    REQUEST(xDamageCreateReq);
30335c4bbdfSmrg    REQUEST_SIZE_MATCH(xDamageCreateReq);
30435c4bbdfSmrg    LEGAL_NEW_RESOURCE(stuff->damage, client);
30535c4bbdfSmrg    doDamageCreate(client, &rc);
30635c4bbdfSmrg    return rc;
30705b261ecSmrg}
30805b261ecSmrg
30905b261ecSmrgstatic int
31035c4bbdfSmrgProcDamageDestroy(ClientPtr client)
31105b261ecSmrg{
31205b261ecSmrg    REQUEST(xDamageDestroyReq);
31335c4bbdfSmrg    DamageExtPtr pDamageExt;
31405b261ecSmrg
31505b261ecSmrg    REQUEST_SIZE_MATCH(xDamageDestroyReq);
31605b261ecSmrg    VERIFY_DAMAGEEXT(pDamageExt, stuff->damage, client, DixWriteAccess);
31735c4bbdfSmrg    FreeResource(stuff->damage, RT_NONE);
3186747b715Smrg    return Success;
31905b261ecSmrg}
32005b261ecSmrg
32135c4bbdfSmrg#ifdef PANORAMIX
32235c4bbdfSmrgstatic RegionPtr
32335c4bbdfSmrgDamageExtSubtractWindowClip(DamageExtPtr pDamageExt)
32435c4bbdfSmrg{
32535c4bbdfSmrg    WindowPtr win = (WindowPtr)pDamageExt->pDrawable;
32635c4bbdfSmrg    PanoramiXRes *res = NULL;
32735c4bbdfSmrg    RegionPtr ret;
32835c4bbdfSmrg    int i;
32935c4bbdfSmrg
33035c4bbdfSmrg    if (!win->parent)
33135c4bbdfSmrg        return &PanoramiXScreenRegion;
33235c4bbdfSmrg
33335c4bbdfSmrg    dixLookupResourceByType((void **)&res, win->drawable.id, XRT_WINDOW,
33435c4bbdfSmrg                            serverClient, DixReadAccess);
33535c4bbdfSmrg    if (!res)
33635c4bbdfSmrg        return NULL;
33735c4bbdfSmrg
33835c4bbdfSmrg    ret = RegionCreate(NULL, 0);
33935c4bbdfSmrg    if (!ret)
34035c4bbdfSmrg        return NULL;
34135c4bbdfSmrg
34235c4bbdfSmrg    FOR_NSCREENS_FORWARD(i) {
34335c4bbdfSmrg        ScreenPtr screen;
34435c4bbdfSmrg        if (Success != dixLookupWindow(&win, res->info[i].id, serverClient,
34535c4bbdfSmrg                                       DixReadAccess))
34635c4bbdfSmrg            goto out;
34735c4bbdfSmrg
34835c4bbdfSmrg        screen = win->drawable.pScreen;
34935c4bbdfSmrg
35035c4bbdfSmrg        RegionTranslate(ret, -screen->x, -screen->y);
35135c4bbdfSmrg        if (!RegionUnion(ret, ret, &win->borderClip))
35235c4bbdfSmrg            goto out;
35335c4bbdfSmrg        RegionTranslate(ret, screen->x, screen->y);
35435c4bbdfSmrg    }
35535c4bbdfSmrg
35635c4bbdfSmrg    return ret;
35735c4bbdfSmrg
35835c4bbdfSmrgout:
35935c4bbdfSmrg    RegionDestroy(ret);
36035c4bbdfSmrg    return NULL;
36135c4bbdfSmrg}
36235c4bbdfSmrg
36335c4bbdfSmrgstatic void
36435c4bbdfSmrgDamageExtFreeWindowClip(RegionPtr reg)
36535c4bbdfSmrg{
36635c4bbdfSmrg    if (reg != &PanoramiXScreenRegion)
36735c4bbdfSmrg        RegionDestroy(reg);
36835c4bbdfSmrg}
36935c4bbdfSmrg#endif
37035c4bbdfSmrg
37135c4bbdfSmrg/*
37235c4bbdfSmrg * DamageSubtract intersects with borderClip, so we must reconstruct the
37335c4bbdfSmrg * protocol's perspective of same...
37435c4bbdfSmrg */
37535c4bbdfSmrgstatic Bool
37635c4bbdfSmrgDamageExtSubtract(DamageExtPtr pDamageExt, const RegionPtr pRegion)
37735c4bbdfSmrg{
37835c4bbdfSmrg    DamagePtr pDamage = pDamageExt->pDamage;
37935c4bbdfSmrg
38035c4bbdfSmrg#ifdef PANORAMIX
38135c4bbdfSmrg    if (!noPanoramiXExtension) {
38235c4bbdfSmrg        RegionPtr damage = DamageRegion(pDamage);
38335c4bbdfSmrg        RegionSubtract(damage, damage, pRegion);
38435c4bbdfSmrg
38535c4bbdfSmrg        if (pDamageExt->pDrawable->type == DRAWABLE_WINDOW) {
38635c4bbdfSmrg            DrawablePtr pDraw = pDamageExt->pDrawable;
38735c4bbdfSmrg            RegionPtr clip = DamageExtSubtractWindowClip(pDamageExt);
38835c4bbdfSmrg            if (clip) {
38935c4bbdfSmrg                RegionTranslate(clip, -pDraw->x, -pDraw->y);
39035c4bbdfSmrg                RegionIntersect(damage, damage, clip);
39135c4bbdfSmrg                RegionTranslate(clip, pDraw->x, pDraw->y);
39235c4bbdfSmrg                DamageExtFreeWindowClip(clip);
39335c4bbdfSmrg            }
39435c4bbdfSmrg        }
39535c4bbdfSmrg
39635c4bbdfSmrg        return RegionNotEmpty(damage);
39735c4bbdfSmrg    }
39835c4bbdfSmrg#endif
39935c4bbdfSmrg
40035c4bbdfSmrg    return DamageSubtract(pDamage, pRegion);
40135c4bbdfSmrg}
40235c4bbdfSmrg
40305b261ecSmrgstatic int
40435c4bbdfSmrgProcDamageSubtract(ClientPtr client)
40505b261ecSmrg{
40605b261ecSmrg    REQUEST(xDamageSubtractReq);
40735c4bbdfSmrg    DamageExtPtr pDamageExt;
40835c4bbdfSmrg    RegionPtr pRepair;
40935c4bbdfSmrg    RegionPtr pParts;
41005b261ecSmrg
41105b261ecSmrg    REQUEST_SIZE_MATCH(xDamageSubtractReq);
41205b261ecSmrg    VERIFY_DAMAGEEXT(pDamageExt, stuff->damage, client, DixWriteAccess);
41305b261ecSmrg    VERIFY_REGION_OR_NONE(pRepair, stuff->repair, client, DixWriteAccess);
41405b261ecSmrg    VERIFY_REGION_OR_NONE(pParts, stuff->parts, client, DixWriteAccess);
41505b261ecSmrg
41635c4bbdfSmrg    if (pDamageExt->level != DamageReportRawRegion) {
41735c4bbdfSmrg        DamagePtr pDamage = pDamageExt->pDamage;
41835c4bbdfSmrg
41935c4bbdfSmrg        if (pRepair) {
42035c4bbdfSmrg            if (pParts)
42135c4bbdfSmrg                RegionIntersect(pParts, DamageRegion(pDamage), pRepair);
42235c4bbdfSmrg            if (DamageExtSubtract(pDamageExt, pRepair))
42335c4bbdfSmrg                DamageExtReport(pDamage, DamageRegion(pDamage),
42435c4bbdfSmrg                                (void *) pDamageExt);
42535c4bbdfSmrg        }
42635c4bbdfSmrg        else {
42735c4bbdfSmrg            if (pParts)
42835c4bbdfSmrg                RegionCopy(pParts, DamageRegion(pDamage));
42935c4bbdfSmrg            DamageEmpty(pDamage);
43035c4bbdfSmrg        }
43105b261ecSmrg    }
43235c4bbdfSmrg
4336747b715Smrg    return Success;
43405b261ecSmrg}
43505b261ecSmrg
43605b261ecSmrgstatic int
43735c4bbdfSmrgProcDamageAdd(ClientPtr client)
43805b261ecSmrg{
43905b261ecSmrg    REQUEST(xDamageAddReq);
44035c4bbdfSmrg    DrawablePtr pDrawable;
44135c4bbdfSmrg    RegionPtr pRegion;
44235c4bbdfSmrg    int rc;
44305b261ecSmrg
44405b261ecSmrg    REQUEST_SIZE_MATCH(xDamageAddReq);
44505b261ecSmrg    VERIFY_REGION(pRegion, stuff->region, client, DixWriteAccess);
44605b261ecSmrg    rc = dixLookupDrawable(&pDrawable, stuff->drawable, client, 0,
44735c4bbdfSmrg                           DixWriteAccess);
44805b261ecSmrg    if (rc != Success)
44935c4bbdfSmrg        return rc;
45005b261ecSmrg
45105b261ecSmrg    /* The region is relative to the drawable origin, so translate it out to
45205b261ecSmrg     * screen coordinates like damage expects.
45305b261ecSmrg     */
4546747b715Smrg    RegionTranslate(pRegion, pDrawable->x, pDrawable->y);
4558223e2f2Smrg    DamageDamageRegion(pDrawable, pRegion);
4566747b715Smrg    RegionTranslate(pRegion, -pDrawable->x, -pDrawable->y);
45705b261ecSmrg
4586747b715Smrg    return Success;
45905b261ecSmrg}
46005b261ecSmrg
46105b261ecSmrg/* Major version controls available requests */
46205b261ecSmrgstatic const int version_requests[] = {
46335c4bbdfSmrg    X_DamageQueryVersion,       /* before client sends QueryVersion */
46435c4bbdfSmrg    X_DamageAdd,                /* Version 1 */
46505b261ecSmrg};
46605b261ecSmrg
46705b261ecSmrg#define NUM_VERSION_REQUESTS	(sizeof (version_requests) / sizeof (version_requests[0]))
46835c4bbdfSmrg
46935c4bbdfSmrgstatic int (*ProcDamageVector[XDamageNumberRequests]) (ClientPtr) = {
47035c4bbdfSmrg    /*************** Version 1 ******************/
47105b261ecSmrg    ProcDamageQueryVersion,
47205b261ecSmrg    ProcDamageCreate,
47305b261ecSmrg    ProcDamageDestroy,
47405b261ecSmrg    ProcDamageSubtract,
47535c4bbdfSmrg    /*************** Version 1.1 ****************/
47605b261ecSmrg    ProcDamageAdd,
47705b261ecSmrg};
47805b261ecSmrg
47905b261ecSmrgstatic int
48035c4bbdfSmrgProcDamageDispatch(ClientPtr client)
48105b261ecSmrg{
48205b261ecSmrg    REQUEST(xDamageReq);
48335c4bbdfSmrg    DamageClientPtr pDamageClient = GetDamageClient(client);
48405b261ecSmrg
48505b261ecSmrg    if (pDamageClient->major_version >= NUM_VERSION_REQUESTS)
48635c4bbdfSmrg        return BadRequest;
48705b261ecSmrg    if (stuff->damageReqType > version_requests[pDamageClient->major_version])
48835c4bbdfSmrg        return BadRequest;
48905b261ecSmrg    return (*ProcDamageVector[stuff->damageReqType]) (client);
49005b261ecSmrg}
49105b261ecSmrg
49205b261ecSmrgstatic int
49305b261ecSmrgSProcDamageQueryVersion(ClientPtr client)
49405b261ecSmrg{
49505b261ecSmrg    REQUEST(xDamageQueryVersionReq);
49605b261ecSmrg
49735c4bbdfSmrg    swaps(&stuff->length);
49805b261ecSmrg    REQUEST_SIZE_MATCH(xDamageQueryVersionReq);
49935c4bbdfSmrg    swapl(&stuff->majorVersion);
50035c4bbdfSmrg    swapl(&stuff->minorVersion);
50105b261ecSmrg    return (*ProcDamageVector[stuff->damageReqType]) (client);
50205b261ecSmrg}
50305b261ecSmrg
50405b261ecSmrgstatic int
50535c4bbdfSmrgSProcDamageCreate(ClientPtr client)
50605b261ecSmrg{
50705b261ecSmrg    REQUEST(xDamageCreateReq);
50835c4bbdfSmrg
50935c4bbdfSmrg    swaps(&stuff->length);
51005b261ecSmrg    REQUEST_SIZE_MATCH(xDamageCreateReq);
51135c4bbdfSmrg    swapl(&stuff->damage);
51235c4bbdfSmrg    swapl(&stuff->drawable);
51305b261ecSmrg    return (*ProcDamageVector[stuff->damageReqType]) (client);
51405b261ecSmrg}
51505b261ecSmrg
51605b261ecSmrgstatic int
51735c4bbdfSmrgSProcDamageDestroy(ClientPtr client)
51805b261ecSmrg{
51905b261ecSmrg    REQUEST(xDamageDestroyReq);
52035c4bbdfSmrg
52135c4bbdfSmrg    swaps(&stuff->length);
52205b261ecSmrg    REQUEST_SIZE_MATCH(xDamageDestroyReq);
52335c4bbdfSmrg    swapl(&stuff->damage);
52405b261ecSmrg    return (*ProcDamageVector[stuff->damageReqType]) (client);
52505b261ecSmrg}
52605b261ecSmrg
52705b261ecSmrgstatic int
52835c4bbdfSmrgSProcDamageSubtract(ClientPtr client)
52905b261ecSmrg{
53005b261ecSmrg    REQUEST(xDamageSubtractReq);
53135c4bbdfSmrg
53235c4bbdfSmrg    swaps(&stuff->length);
53305b261ecSmrg    REQUEST_SIZE_MATCH(xDamageSubtractReq);
53435c4bbdfSmrg    swapl(&stuff->damage);
53535c4bbdfSmrg    swapl(&stuff->repair);
53635c4bbdfSmrg    swapl(&stuff->parts);
53705b261ecSmrg    return (*ProcDamageVector[stuff->damageReqType]) (client);
53805b261ecSmrg}
53905b261ecSmrg
54005b261ecSmrgstatic int
54135c4bbdfSmrgSProcDamageAdd(ClientPtr client)
54205b261ecSmrg{
54305b261ecSmrg    REQUEST(xDamageAddReq);
54405b261ecSmrg
54535c4bbdfSmrg    swaps(&stuff->length);
54605b261ecSmrg    REQUEST_SIZE_MATCH(xDamageSubtractReq);
54735c4bbdfSmrg    swapl(&stuff->drawable);
54835c4bbdfSmrg    swapl(&stuff->region);
54905b261ecSmrg    return (*ProcDamageVector[stuff->damageReqType]) (client);
55005b261ecSmrg}
55105b261ecSmrg
55235c4bbdfSmrgstatic int (*SProcDamageVector[XDamageNumberRequests]) (ClientPtr) = {
55335c4bbdfSmrg    /*************** Version 1 ******************/
55405b261ecSmrg    SProcDamageQueryVersion,
55505b261ecSmrg    SProcDamageCreate,
55605b261ecSmrg    SProcDamageDestroy,
55705b261ecSmrg    SProcDamageSubtract,
55835c4bbdfSmrg    /*************** Version 1.1 ****************/
55905b261ecSmrg    SProcDamageAdd,
56005b261ecSmrg};
56105b261ecSmrg
56205b261ecSmrgstatic int
56335c4bbdfSmrgSProcDamageDispatch(ClientPtr client)
56405b261ecSmrg{
56505b261ecSmrg    REQUEST(xDamageReq);
56605b261ecSmrg    if (stuff->damageReqType >= XDamageNumberRequests)
56735c4bbdfSmrg        return BadRequest;
56805b261ecSmrg    return (*SProcDamageVector[stuff->damageReqType]) (client);
56905b261ecSmrg}
57005b261ecSmrg
57105b261ecSmrgstatic void
57235c4bbdfSmrgDamageClientCallback(CallbackListPtr *list, void *closure, void *data)
57305b261ecSmrg{
57435c4bbdfSmrg    NewClientInfoRec *clientinfo = (NewClientInfoRec *) data;
57535c4bbdfSmrg    ClientPtr pClient = clientinfo->client;
57635c4bbdfSmrg    DamageClientPtr pDamageClient = GetDamageClient(pClient);
57705b261ecSmrg
57805b261ecSmrg    pDamageClient->critical = 0;
57905b261ecSmrg    pDamageClient->major_version = 0;
58005b261ecSmrg    pDamageClient->minor_version = 0;
58105b261ecSmrg}
58205b261ecSmrg
58335c4bbdfSmrg /*ARGSUSED*/ static void
58435c4bbdfSmrgDamageResetProc(ExtensionEntry * extEntry)
58505b261ecSmrg{
58635c4bbdfSmrg    DeleteCallback(&ClientStateCallback, DamageClientCallback, 0);
58705b261ecSmrg}
58805b261ecSmrg
58905b261ecSmrgstatic int
59035c4bbdfSmrgFreeDamageExt(void *value, XID did)
59105b261ecSmrg{
59235c4bbdfSmrg    DamageExtPtr pDamageExt = (DamageExtPtr) value;
59305b261ecSmrg
59405b261ecSmrg    /*
59505b261ecSmrg     * Get rid of the resource table entry hanging from the window id
59605b261ecSmrg     */
59705b261ecSmrg    pDamageExt->id = 0;
59835c4bbdfSmrg    if (pDamageExt->pDamage) {
59935c4bbdfSmrg        DamageDestroy(pDamageExt->pDamage);
60005b261ecSmrg    }
6016747b715Smrg    free(pDamageExt);
60205b261ecSmrg    return Success;
60305b261ecSmrg}
60405b261ecSmrg
60535c4bbdfSmrgstatic void
60635c4bbdfSmrgSDamageNotifyEvent(xDamageNotifyEvent * from, xDamageNotifyEvent * to)
60705b261ecSmrg{
60835c4bbdfSmrg    to->type = from->type;
60935c4bbdfSmrg    cpswaps(from->sequenceNumber, to->sequenceNumber);
61035c4bbdfSmrg    cpswapl(from->drawable, to->drawable);
61135c4bbdfSmrg    cpswapl(from->damage, to->damage);
61235c4bbdfSmrg    cpswaps(from->area.x, to->area.x);
61335c4bbdfSmrg    cpswaps(from->area.y, to->area.y);
61435c4bbdfSmrg    cpswaps(from->area.width, to->area.width);
61535c4bbdfSmrg    cpswaps(from->area.height, to->area.height);
61635c4bbdfSmrg    cpswaps(from->geometry.x, to->geometry.x);
61735c4bbdfSmrg    cpswaps(from->geometry.y, to->geometry.y);
61835c4bbdfSmrg    cpswaps(from->geometry.width, to->geometry.width);
61935c4bbdfSmrg    cpswaps(from->geometry.height, to->geometry.height);
62035c4bbdfSmrg}
62105b261ecSmrg
62235c4bbdfSmrg#ifdef PANORAMIX
62335c4bbdfSmrg
62435c4bbdfSmrgstatic void
62535c4bbdfSmrgPanoramiXDamageReport(DamagePtr pDamage, RegionPtr pRegion, void *closure)
62635c4bbdfSmrg{
62735c4bbdfSmrg    PanoramiXDamageRes *res = closure;
62835c4bbdfSmrg    DamageExtPtr pDamageExt = res->ext;
62935c4bbdfSmrg    WindowPtr pWin = (WindowPtr)pDamage->pDrawable;
63035c4bbdfSmrg    ScreenPtr pScreen = pDamage->pScreen;
63135c4bbdfSmrg
63235c4bbdfSmrg    /* happens on unmap? sigh xinerama */
63335c4bbdfSmrg    if (RegionNil(pRegion))
63435c4bbdfSmrg        return;
63535c4bbdfSmrg
63635c4bbdfSmrg    /* translate root windows if necessary */
63735c4bbdfSmrg    if (!pWin->parent)
63835c4bbdfSmrg        RegionTranslate(pRegion, pScreen->x, pScreen->y);
63935c4bbdfSmrg
64035c4bbdfSmrg    /* add our damage to the protocol view */
64135c4bbdfSmrg    DamageReportDamage(pDamageExt->pDamage, pRegion);
64235c4bbdfSmrg
64335c4bbdfSmrg    /* empty our view */
64435c4bbdfSmrg    DamageEmpty(pDamage);
64505b261ecSmrg}
64605b261ecSmrg
64705b261ecSmrgstatic void
64835c4bbdfSmrgPanoramiXDamageExtDestroy(DamagePtr pDamage, void *closure)
64905b261ecSmrg{
65035c4bbdfSmrg    PanoramiXDamageRes *damage = closure;
65135c4bbdfSmrg    damage->damage[pDamage->pScreen->myNum] = NULL;
65205b261ecSmrg}
65305b261ecSmrg
65435c4bbdfSmrgstatic int
65535c4bbdfSmrgPanoramiXDamageCreate(ClientPtr client)
65635c4bbdfSmrg{
65735c4bbdfSmrg    PanoramiXDamageRes *damage;
65835c4bbdfSmrg    PanoramiXRes *draw;
65935c4bbdfSmrg    int i, rc;
66035c4bbdfSmrg
66135c4bbdfSmrg    REQUEST(xDamageCreateReq);
66235c4bbdfSmrg
66335c4bbdfSmrg    REQUEST_SIZE_MATCH(xDamageCreateReq);
66435c4bbdfSmrg    LEGAL_NEW_RESOURCE(stuff->damage, client);
66535c4bbdfSmrg    rc = dixLookupResourceByClass((void **)&draw, stuff->drawable, XRC_DRAWABLE,
66635c4bbdfSmrg                                  client, DixGetAttrAccess | DixReadAccess);
66735c4bbdfSmrg    if (rc != Success)
66835c4bbdfSmrg        return rc;
66935c4bbdfSmrg
67035c4bbdfSmrg    if (!(damage = calloc(1, sizeof(PanoramiXDamageRes))))
67135c4bbdfSmrg        return BadAlloc;
67235c4bbdfSmrg
67335c4bbdfSmrg    if (!AddResource(stuff->damage, XRT_DAMAGE, damage))
67435c4bbdfSmrg        return BadAlloc;
67535c4bbdfSmrg
67635c4bbdfSmrg    damage->ext = doDamageCreate(client, &rc);
67735c4bbdfSmrg    if (rc == Success && draw->type == XRT_WINDOW) {
67835c4bbdfSmrg        FOR_NSCREENS_FORWARD(i) {
67935c4bbdfSmrg            DrawablePtr pDrawable;
68035c4bbdfSmrg            DamagePtr pDamage = DamageCreate(PanoramiXDamageReport,
68135c4bbdfSmrg                                             PanoramiXDamageExtDestroy,
68235c4bbdfSmrg                                             DamageReportRawRegion,
68335c4bbdfSmrg                                             FALSE,
68435c4bbdfSmrg                                             screenInfo.screens[i],
68535c4bbdfSmrg                                             damage);
68635c4bbdfSmrg            if (!pDamage) {
68735c4bbdfSmrg                rc = BadAlloc;
68835c4bbdfSmrg            } else {
68935c4bbdfSmrg                damage->damage[i] = pDamage;
69035c4bbdfSmrg                rc = dixLookupDrawable(&pDrawable, draw->info[i].id, client,
69135c4bbdfSmrg                                       M_WINDOW,
69235c4bbdfSmrg                                       DixGetAttrAccess | DixReadAccess);
69335c4bbdfSmrg            }
69435c4bbdfSmrg            if (rc != Success)
69535c4bbdfSmrg                break;
69635c4bbdfSmrg
69735c4bbdfSmrg            DamageExtRegister(pDrawable, pDamage, i != 0);
69835c4bbdfSmrg        }
69935c4bbdfSmrg    }
70035c4bbdfSmrg
70135c4bbdfSmrg    if (rc != Success)
70235c4bbdfSmrg        FreeResource(stuff->damage, RT_NONE);
70335c4bbdfSmrg
70435c4bbdfSmrg    return rc;
70535c4bbdfSmrg}
70635c4bbdfSmrg
70735c4bbdfSmrgstatic int
70835c4bbdfSmrgPanoramiXDamageDelete(void *res, XID id)
70935c4bbdfSmrg{
71035c4bbdfSmrg    int i;
71135c4bbdfSmrg    PanoramiXDamageRes *damage = res;
71235c4bbdfSmrg
71335c4bbdfSmrg    FOR_NSCREENS_BACKWARD(i) {
71435c4bbdfSmrg        if (damage->damage[i]) {
71535c4bbdfSmrg            DamageDestroy(damage->damage[i]);
71635c4bbdfSmrg            damage->damage[i] = NULL;
71735c4bbdfSmrg        }
71835c4bbdfSmrg    }
71935c4bbdfSmrg
72035c4bbdfSmrg    free(damage);
72135c4bbdfSmrg    return 1;
72235c4bbdfSmrg}
72335c4bbdfSmrg
72435c4bbdfSmrgvoid
72535c4bbdfSmrgPanoramiXDamageInit(void)
72635c4bbdfSmrg{
72735c4bbdfSmrg    XRT_DAMAGE = CreateNewResourceType(PanoramiXDamageDelete, "XineramaDamage");
72835c4bbdfSmrg    if (!XRT_DAMAGE)
72935c4bbdfSmrg        FatalError("Couldn't Xineramify Damage extension\n");
73035c4bbdfSmrg
73135c4bbdfSmrg    PanoramiXSaveDamageCreate = ProcDamageVector[X_DamageCreate];
73235c4bbdfSmrg    ProcDamageVector[X_DamageCreate] = PanoramiXDamageCreate;
73335c4bbdfSmrg}
73435c4bbdfSmrg
73535c4bbdfSmrgvoid
73635c4bbdfSmrgPanoramiXDamageReset(void)
73735c4bbdfSmrg{
73835c4bbdfSmrg    ProcDamageVector[X_DamageCreate] = PanoramiXSaveDamageCreate;
73935c4bbdfSmrg}
74035c4bbdfSmrg
74135c4bbdfSmrg#endif /* PANORAMIX */
74235c4bbdfSmrg
74305b261ecSmrgvoid
74405b261ecSmrgDamageExtensionInit(void)
74505b261ecSmrg{
74605b261ecSmrg    ExtensionEntry *extEntry;
74735c4bbdfSmrg    int s;
74805b261ecSmrg
74905b261ecSmrg    for (s = 0; s < screenInfo.numScreens; s++)
75035c4bbdfSmrg        DamageSetup(screenInfo.screens[s]);
75105b261ecSmrg
75235c4bbdfSmrg    DamageExtType = CreateNewResourceType(FreeDamageExt, "DamageExt");
75305b261ecSmrg    if (!DamageExtType)
75435c4bbdfSmrg        return;
75535c4bbdfSmrg
75635c4bbdfSmrg    if (!dixRegisterPrivateKey
75735c4bbdfSmrg        (&DamageClientPrivateKeyRec, PRIVATE_CLIENT, sizeof(DamageClientRec)))
75835c4bbdfSmrg        return;
75935c4bbdfSmrg
76035c4bbdfSmrg    if (!AddCallback(&ClientStateCallback, DamageClientCallback, 0))
76135c4bbdfSmrg        return;
76235c4bbdfSmrg
76335c4bbdfSmrg    if ((extEntry = AddExtension(DAMAGE_NAME, XDamageNumberEvents,
76435c4bbdfSmrg                                 XDamageNumberErrors,
76535c4bbdfSmrg                                 ProcDamageDispatch, SProcDamageDispatch,
76635c4bbdfSmrg                                 DamageResetProc, StandardMinorOpcode)) != 0) {
76735c4bbdfSmrg        DamageReqCode = (unsigned char) extEntry->base;
76835c4bbdfSmrg        DamageEventBase = extEntry->eventBase;
76935c4bbdfSmrg        EventSwapVector[DamageEventBase + XDamageNotify] =
77035c4bbdfSmrg            (EventSwapPtr) SDamageNotifyEvent;
77135c4bbdfSmrg        SetResourceTypeErrorValue(DamageExtType,
77235c4bbdfSmrg                                  extEntry->errorBase + BadDamage);
77335c4bbdfSmrg#ifdef PANORAMIX
77435c4bbdfSmrg        if (XRT_DAMAGE)
77535c4bbdfSmrg            SetResourceTypeErrorValue(XRT_DAMAGE,
77635c4bbdfSmrg                                      extEntry->errorBase + BadDamage);
77735c4bbdfSmrg#endif
77805b261ecSmrg    }
77905b261ecSmrg}
780