Imported Upstream version 1.15.1
[deb_xorg-server.git] / damageext / damageext.c
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
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
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
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
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
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
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
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
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
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, (pointer) pDamageExt))
249 return NULL;
250
251 DamageExtRegister(pDrawable, pDamageExt->pDamage,
252 pDrawable->type == DRAWABLE_WINDOW);
253
254 return pDamageExt;
255 }
256
257 static DamageExtPtr
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
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
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
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
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
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
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
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 #define NUM_VERSION_REQUESTS (sizeof (version_requests) / sizeof (version_requests[0]))
468
469 static int (*ProcDamageVector[XDamageNumberRequests]) (ClientPtr) = {
470 /*************** Version 1 ******************/
471 ProcDamageQueryVersion,
472 ProcDamageCreate,
473 ProcDamageDestroy,
474 ProcDamageSubtract,
475 /*************** Version 1.1 ****************/
476 ProcDamageAdd,
477 };
478
479 static int
480 ProcDamageDispatch(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
492 static int
493 SProcDamageQueryVersion(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
504 static int
505 SProcDamageCreate(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
516 static int
517 SProcDamageDestroy(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
527 static int
528 SProcDamageSubtract(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
540 static int
541 SProcDamageAdd(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
552 static int (*SProcDamageVector[XDamageNumberRequests]) (ClientPtr) = {
553 /*************** Version 1 ******************/
554 SProcDamageQueryVersion,
555 SProcDamageCreate,
556 SProcDamageDestroy,
557 SProcDamageSubtract,
558 /*************** Version 1.1 ****************/
559 SProcDamageAdd,
560 };
561
562 static int
563 SProcDamageDispatch(ClientPtr client)
564 {
565 REQUEST(xDamageReq);
566 if (stuff->damageReqType >= XDamageNumberRequests)
567 return BadRequest;
568 return (*SProcDamageVector[stuff->damageReqType]) (client);
569 }
570
571 static void
572 DamageClientCallback(CallbackListPtr *list, pointer closure, pointer 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
584 DamageResetProc(ExtensionEntry * extEntry)
585 {
586 DeleteCallback(&ClientStateCallback, DamageClientCallback, 0);
587 }
588
589 static int
590 FreeDamageExt(pointer 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
605 static void
606 SDamageNotifyEvent(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
624 static void
625 PanoramiXDamageReport(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
647 static void
648 PanoramiXDamageExtDestroy(DamagePtr pDamage, void *closure)
649 {
650 PanoramiXDamageRes *damage = closure;
651 damage->damage[pDamage->pScreen->myNum] = NULL;
652 }
653
654 static int
655 PanoramiXDamageCreate(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
707 static int
708 PanoramiXDamageDelete(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
724 void
725 PanoramiXDamageInit(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
735 void
736 PanoramiXDamageReset(void)
737 {
738 ProcDamageVector[X_DamageCreate] = PanoramiXSaveDamageCreate;
739 }
740
741 #endif /* PANORAMIX */
742
743 void
744 DamageExtensionInit(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 }