Use correct swap{l,s} (or none at all for CARD8)
[gstreamer-omap:xserver.git] / randr / rrcrtc.c
1 /*
2  * Copyright © 2006 Keith Packard
3  * Copyright 2010 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 copyright
8  * notice and this permission notice appear in supporting documentation, and
9  * that the name of the copyright holders not be used in advertising or
10  * publicity pertaining to distribution of the software without specific,
11  * written prior permission.  The copyright holders make no representations
12  * about the suitability of this software for any purpose.  It is provided "as
13  * is" without express or implied warranty.
14  *
15  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
17  * EVENT SHALL THE COPYRIGHT HOLDERS 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 PERFORMANCE
21  * OF THIS SOFTWARE.
22  */
23
24 #include "randrstr.h"
25 #include "swaprep.h"
26 #include "mipointer.h"
27
28 RESTYPE RRCrtcType;
29
30 /*
31  * Notify the CRTC of some change
32  */
33 void
34 RRCrtcChanged (RRCrtcPtr crtc, Bool layoutChanged)
35 {
36     ScreenPtr   pScreen = crtc->pScreen;
37
38     crtc->changed = TRUE;
39     if (pScreen)
40     {
41         rrScrPriv(pScreen);
42     
43         pScrPriv->changed = TRUE;
44         /*
45          * Send ConfigureNotify on any layout change
46          */
47         if (layoutChanged)
48             pScrPriv->layoutChanged = TRUE;
49     }
50 }
51
52 /*
53  * Create a CRTC
54  */
55 RRCrtcPtr
56 RRCrtcCreate (ScreenPtr pScreen, void *devPrivate)
57 {
58     RRCrtcPtr       crtc;
59     RRCrtcPtr       *crtcs;
60     rrScrPrivPtr    pScrPriv;
61
62     if (!RRInit())
63         return NULL;
64     
65     pScrPriv = rrGetScrPriv(pScreen);
66
67     /* make space for the crtc pointer */
68     if (pScrPriv->numCrtcs)
69         crtcs = realloc(pScrPriv->crtcs, 
70                           (pScrPriv->numCrtcs + 1) * sizeof (RRCrtcPtr));
71     else
72         crtcs = malloc(sizeof (RRCrtcPtr));
73     if (!crtcs)
74         return FALSE;
75     pScrPriv->crtcs = crtcs;
76     
77     crtc = calloc(1, sizeof (RRCrtcRec));
78     if (!crtc)
79         return NULL;
80     crtc->id = FakeClientID (0);
81     crtc->pScreen = pScreen;
82     crtc->mode = NULL;
83     crtc->x = 0;
84     crtc->y = 0;
85     crtc->rotation = RR_Rotate_0;
86     crtc->rotations = RR_Rotate_0;
87     crtc->outputs = NULL;
88     crtc->numOutputs = 0;
89     crtc->gammaSize = 0;
90     crtc->gammaRed = crtc->gammaBlue = crtc->gammaGreen = NULL;
91     crtc->changed = FALSE;
92     crtc->devPrivate = devPrivate;
93     RRTransformInit (&crtc->client_pending_transform);
94     RRTransformInit (&crtc->client_current_transform);
95     pixman_transform_init_identity (&crtc->transform);
96     pixman_f_transform_init_identity (&crtc->f_transform);
97     pixman_f_transform_init_identity (&crtc->f_inverse);
98
99     if (!AddResource (crtc->id, RRCrtcType, (pointer) crtc))
100         return NULL;
101
102     /* attach the screen and crtc together */
103     crtc->pScreen = pScreen;
104     pScrPriv->crtcs[pScrPriv->numCrtcs++] = crtc;
105     
106     return crtc;
107 }
108
109 /*
110  * Set the allowed rotations on a CRTC
111  */
112 void
113 RRCrtcSetRotations (RRCrtcPtr crtc, Rotation rotations)
114 {
115     crtc->rotations = rotations;
116 }
117
118 /*
119  * Set whether transforms are allowed on a CRTC
120  */
121 void
122 RRCrtcSetTransformSupport (RRCrtcPtr crtc, Bool transforms)
123 {
124     crtc->transforms = transforms;
125 }
126
127 /*
128  * Notify the extension that the Crtc has been reconfigured,
129  * the driver calls this whenever it has updated the mode
130  */
131 Bool
132 RRCrtcNotify (RRCrtcPtr     crtc,
133               RRModePtr     mode,
134               int           x,
135               int           y,
136               Rotation      rotation,
137               RRTransformPtr transform,
138               int           numOutputs,
139               RROutputPtr   *outputs)
140 {
141     int     i, j;
142     
143     /*
144      * Check to see if any of the new outputs were
145      * not in the old list and mark them as changed
146      */
147     for (i = 0; i < numOutputs; i++)
148     {
149         for (j = 0; j < crtc->numOutputs; j++)
150             if (outputs[i] == crtc->outputs[j])
151                 break;
152         if (j == crtc->numOutputs)
153         {
154             outputs[i]->crtc = crtc;
155             RROutputChanged (outputs[i], FALSE);
156             RRCrtcChanged (crtc, FALSE);
157         }
158     }
159     /*
160      * Check to see if any of the old outputs are
161      * not in the new list and mark them as changed
162      */
163     for (j = 0; j < crtc->numOutputs; j++)
164     {
165         for (i = 0; i < numOutputs; i++)
166             if (outputs[i] == crtc->outputs[j])
167                 break;
168         if (i == numOutputs)
169         {
170             if (crtc->outputs[j]->crtc == crtc)
171                 crtc->outputs[j]->crtc = NULL;
172             RROutputChanged (crtc->outputs[j], FALSE);
173             RRCrtcChanged (crtc, FALSE);
174         }
175     }
176     /*
177      * Reallocate the crtc output array if necessary
178      */
179     if (numOutputs != crtc->numOutputs)
180     {
181         RROutputPtr *newoutputs;
182         
183         if (numOutputs)
184         {
185             if (crtc->numOutputs)
186                 newoutputs = realloc(crtc->outputs,
187                                     numOutputs * sizeof (RROutputPtr));
188             else
189                 newoutputs = malloc(numOutputs * sizeof (RROutputPtr));
190             if (!newoutputs)
191                 return FALSE;
192         }
193         else
194         {
195             free(crtc->outputs);
196             newoutputs = NULL;
197         }
198         crtc->outputs = newoutputs;
199         crtc->numOutputs = numOutputs;
200     }
201     /*
202      * Copy the new list of outputs into the crtc
203      */
204     memcpy (crtc->outputs, outputs, numOutputs * sizeof (RROutputPtr));
205     /*
206      * Update remaining crtc fields
207      */
208     if (mode != crtc->mode)
209     {
210         if (crtc->mode)
211             RRModeDestroy (crtc->mode);
212         crtc->mode = mode;
213         if (mode != NULL)
214             mode->refcnt++;
215         RRCrtcChanged (crtc, TRUE);
216     }
217     if (x != crtc->x)
218     {
219         crtc->x = x;
220         RRCrtcChanged (crtc, TRUE);
221     }
222     if (y != crtc->y)
223     {
224         crtc->y = y;
225         RRCrtcChanged (crtc, TRUE);
226     }
227     if (rotation != crtc->rotation)
228     {
229         crtc->rotation = rotation;
230         RRCrtcChanged (crtc, TRUE);
231     }
232     if (!RRTransformEqual (transform, &crtc->client_current_transform)) {
233         RRTransformCopy (&crtc->client_current_transform, transform);
234         RRCrtcChanged (crtc, TRUE);
235     }
236     if (crtc->changed && mode)
237     {
238         RRTransformCompute (x, y,
239                             mode->mode.width, mode->mode.height,
240                             rotation,
241                             &crtc->client_current_transform,
242                             &crtc->transform, &crtc->f_transform,
243                             &crtc->f_inverse);
244     }
245     return TRUE;
246 }
247
248 void
249 RRDeliverCrtcEvent (ClientPtr client, WindowPtr pWin, RRCrtcPtr crtc)
250 {
251     ScreenPtr pScreen = pWin->drawable.pScreen;
252     rrScrPriv (pScreen);
253     xRRCrtcChangeNotifyEvent    ce;
254     RRModePtr   mode = crtc->mode;
255     
256     ce.type = RRNotify + RREventBase;
257     ce.subCode = RRNotify_CrtcChange;
258     ce.timestamp = pScrPriv->lastSetTime.milliseconds;
259     ce.window = pWin->drawable.id;
260     ce.crtc = crtc->id;
261     ce.rotation = crtc->rotation;
262     if (mode)
263     {
264         ce.mode = mode->mode.id;
265         ce.x = crtc->x;
266         ce.y = crtc->y;
267         ce.width = mode->mode.width;
268         ce.height = mode->mode.height;
269     }
270     else
271     {
272         ce.mode = None;
273         ce.x = 0;
274         ce.y = 0;
275         ce.width = 0;
276         ce.height = 0;
277     }
278     WriteEventsToClient (client, 1, (xEvent *) &ce);
279 }
280
281 static Bool
282 RRCrtcPendingProperties (RRCrtcPtr crtc)
283 {
284     ScreenPtr   pScreen = crtc->pScreen;
285     rrScrPriv(pScreen);
286     int         o;
287
288     for (o = 0; o < pScrPriv->numOutputs; o++)
289     {
290         RROutputPtr output = pScrPriv->outputs[o];
291         if (output->crtc == crtc && output->pendingProperties)
292             return TRUE;
293     }
294     return FALSE;
295 }
296
297 static void
298 crtc_bounds(RRCrtcPtr crtc, int *left, int *right, int *top, int *bottom)
299 {
300     *left = crtc->x;
301     *top = crtc->y;
302
303     switch (crtc->rotation) {
304     case RR_Rotate_0:
305     case RR_Rotate_180:
306     default:
307        *right = crtc->x + crtc->mode->mode.width;
308        *bottom = crtc->y + crtc->mode->mode.height;
309        return;
310     case RR_Rotate_90:
311     case RR_Rotate_270:
312        *right = crtc->x + crtc->mode->mode.height;
313        *bottom = crtc->y + crtc->mode->mode.width;
314        return;
315     }
316 }
317
318 /* overlapping counts as adjacent */
319 static Bool
320 crtcs_adjacent(const RRCrtcPtr a, const RRCrtcPtr b)
321 {
322     /* left, right, top, bottom... */
323     int al, ar, at, ab;
324     int bl, br, bt, bb;
325     int cl, cr, ct, cb; /* the overlap, if any */
326
327     crtc_bounds(a, &al, &ar, &at, &ab);
328     crtc_bounds(b, &bl, &br, &bt, &bb);
329
330     cl = max(al, bl);
331     cr = min(ar, br);
332     ct = max(at, bt);
333     cb = min(ab, bb);
334
335     return (cl <= cr) && (ct <= cb);
336 }
337
338 /* Depth-first search and mark all CRTCs reachable from cur */
339 static void
340 mark_crtcs (rrScrPrivPtr pScrPriv, int *reachable, int cur)
341 {
342     int i;
343     reachable[cur] = TRUE;
344     for (i = 0; i < pScrPriv->numCrtcs; ++i) {
345         if (reachable[i] || !pScrPriv->crtcs[i]->mode)
346             continue;
347         if (crtcs_adjacent(pScrPriv->crtcs[cur], pScrPriv->crtcs[i]))
348             mark_crtcs(pScrPriv, reachable, i);
349     }
350 }
351
352 static void
353 RRComputeContiguity (ScreenPtr pScreen)
354 {
355     rrScrPriv(pScreen);
356     Bool discontiguous = TRUE;
357     int i, n = pScrPriv->numCrtcs;
358
359     int *reachable = calloc(n, sizeof(int));
360     if (!reachable)
361         goto out;
362
363     /* Find first enabled CRTC and start search for reachable CRTCs from it */
364     for (i = 0; i < n; ++i) {
365         if (pScrPriv->crtcs[i]->mode) {
366             mark_crtcs(pScrPriv, reachable, i);
367             break;
368         }
369     }
370
371     /* Check that all enabled CRTCs were marked as reachable */
372     for (i = 0; i < n; ++i)
373         if (pScrPriv->crtcs[i]->mode && !reachable[i])
374             goto out;
375
376     discontiguous = FALSE;
377
378 out:
379     free(reachable);
380     pScrPriv->discontiguous = discontiguous;
381 }
382
383 /*
384  * Request that the Crtc be reconfigured
385  */
386 Bool
387 RRCrtcSet (RRCrtcPtr    crtc,
388            RRModePtr    mode,
389            int          x,
390            int          y,
391            Rotation     rotation,
392            int          numOutputs,
393            RROutputPtr  *outputs)
394 {
395     ScreenPtr   pScreen = crtc->pScreen;
396     Bool        ret = FALSE;
397     Bool        recompute = TRUE;
398     rrScrPriv(pScreen);
399
400     /* See if nothing changed */
401     if (crtc->mode == mode &&
402         crtc->x == x &&
403         crtc->y == y &&
404         crtc->rotation == rotation &&
405         crtc->numOutputs == numOutputs &&
406         !memcmp (crtc->outputs, outputs, numOutputs * sizeof (RROutputPtr)) &&
407         !RRCrtcPendingProperties (crtc) &&
408         !RRCrtcPendingTransform (crtc))
409     {
410         recompute = FALSE;
411         ret = TRUE;
412     }
413     else
414     {
415 #if RANDR_12_INTERFACE
416         if (pScrPriv->rrCrtcSet)
417         {
418             ret = (*pScrPriv->rrCrtcSet) (pScreen, crtc, mode, x, y, 
419                                           rotation, numOutputs, outputs);
420         }
421         else
422 #endif
423         {
424 #if RANDR_10_INTERFACE
425             if (pScrPriv->rrSetConfig)
426             {
427                 RRScreenSize        size;
428                 RRScreenRate        rate;
429
430                 if (!mode)
431                 {
432                     RRCrtcNotify (crtc, NULL, x, y, rotation, NULL, 0, NULL);
433                     ret = TRUE;
434                 }
435                 else
436                 {
437                     size.width = mode->mode.width;
438                     size.height = mode->mode.height;
439                     if (outputs[0]->mmWidth && outputs[0]->mmHeight)
440                     {
441                         size.mmWidth = outputs[0]->mmWidth;
442                         size.mmHeight = outputs[0]->mmHeight;
443                     }
444                     else
445                     {
446                         size.mmWidth = pScreen->mmWidth;
447                         size.mmHeight = pScreen->mmHeight;
448                     }
449                     size.nRates = 1;
450                     rate.rate = RRVerticalRefresh (&mode->mode);
451                     size.pRates = &rate;
452                     ret = (*pScrPriv->rrSetConfig) (pScreen, rotation, rate.rate, &size);
453                     /*
454                      * Old 1.0 interface tied screen size to mode size
455                      */
456                     if (ret)
457                     {
458                         RRCrtcNotify (crtc, mode, x, y, rotation, NULL, 1, outputs);
459                         RRScreenSizeNotify (pScreen);
460                     }
461                 }
462             }
463 #endif
464         }
465         if (ret)
466         {
467             int o;
468             RRTellChanged (pScreen);
469
470             for (o = 0; o < numOutputs; o++)
471                 RRPostPendingProperties (outputs[o]);
472         }
473     }
474
475     if (recompute)
476        RRComputeContiguity(pScreen);
477
478     return ret;
479 }
480
481 /*
482  * Return crtc transform
483  */
484 RRTransformPtr
485 RRCrtcGetTransform (RRCrtcPtr crtc)
486 {
487     RRTransformPtr  transform = &crtc->client_pending_transform;
488
489     if (pixman_transform_is_identity (&transform->transform))
490         return NULL;
491     return transform;
492 }
493
494 /*
495  * Check whether the pending and current transforms are the same
496  */
497 Bool
498 RRCrtcPendingTransform (RRCrtcPtr crtc)
499 {
500     return memcmp (&crtc->client_current_transform.transform,
501                    &crtc->client_pending_transform.transform,
502                    sizeof (PictTransform)) != 0;
503 }
504
505 /*
506  * Destroy a Crtc at shutdown
507  */
508 void
509 RRCrtcDestroy (RRCrtcPtr crtc)
510 {
511     FreeResource (crtc->id, 0);
512 }
513
514 static int
515 RRCrtcDestroyResource (pointer value, XID pid)
516 {
517     RRCrtcPtr   crtc = (RRCrtcPtr) value;
518     ScreenPtr   pScreen = crtc->pScreen;
519
520     if (pScreen)
521     {
522         rrScrPriv(pScreen);
523         int             i;
524     
525         for (i = 0; i < pScrPriv->numCrtcs; i++)
526         {
527             if (pScrPriv->crtcs[i] == crtc)
528             {
529                 memmove (pScrPriv->crtcs + i, pScrPriv->crtcs + i + 1,
530                          (pScrPriv->numCrtcs - (i + 1)) * sizeof (RRCrtcPtr));
531                 --pScrPriv->numCrtcs;
532                 break;
533             }
534         }
535     }
536     free(crtc->gammaRed);
537     if (crtc->mode)
538         RRModeDestroy (crtc->mode);
539     free(crtc);
540     return 1;
541 }
542
543 /*
544  * Request that the Crtc gamma be changed
545  */
546
547 Bool
548 RRCrtcGammaSet (RRCrtcPtr   crtc,
549                 CARD16      *red,
550                 CARD16      *green,
551                 CARD16      *blue)
552 {
553     Bool        ret = TRUE;
554 #if RANDR_12_INTERFACE
555     ScreenPtr   pScreen = crtc->pScreen;
556 #endif
557     
558     memcpy (crtc->gammaRed, red, crtc->gammaSize * sizeof (CARD16));
559     memcpy (crtc->gammaGreen, green, crtc->gammaSize * sizeof (CARD16));
560     memcpy (crtc->gammaBlue, blue, crtc->gammaSize * sizeof (CARD16));
561 #if RANDR_12_INTERFACE
562     if (pScreen)
563     {
564         rrScrPriv(pScreen);
565         if (pScrPriv->rrCrtcSetGamma)
566             ret = (*pScrPriv->rrCrtcSetGamma) (pScreen, crtc);
567     }
568 #endif
569     return ret;
570 }
571
572 /*
573  * Request current gamma back from the DDX (if possible).
574  * This includes gamma size.
575  */
576 Bool
577 RRCrtcGammaGet(RRCrtcPtr crtc)
578 {
579     Bool ret = TRUE;
580 #if RANDR_12_INTERFACE
581     ScreenPtr   pScreen = crtc->pScreen;
582 #endif
583
584 #if RANDR_12_INTERFACE
585     if (pScreen)
586     {
587         rrScrPriv(pScreen);
588         if (pScrPriv->rrCrtcGetGamma)
589             ret = (*pScrPriv->rrCrtcGetGamma) (pScreen, crtc);
590     }
591 #endif
592     return ret;
593 }
594
595 /*
596  * Notify the extension that the Crtc gamma has been changed
597  * The driver calls this whenever it has changed the gamma values
598  * in the RRCrtcRec
599  */
600
601 Bool
602 RRCrtcGammaNotify (RRCrtcPtr    crtc)
603 {
604     return TRUE;    /* not much going on here */
605 }
606
607 static void
608 RRModeGetScanoutSize (RRModePtr mode, PictTransformPtr transform,
609                       int *width, int *height)
610 {
611     BoxRec  box;
612
613     if (mode == NULL) {
614         *width = 0;
615         *height = 0;
616         return;
617     }
618
619     box.x1 = 0;
620     box.y1 = 0;
621     box.x2 = mode->mode.width;
622     box.y2 = mode->mode.height;
623
624     pixman_transform_bounds (transform, &box);
625     *width = box.x2 - box.x1;
626     *height = box.y2 - box.y1;
627 }
628
629 /**
630  * Returns the width/height that the crtc scans out from the framebuffer
631  */
632 void
633 RRCrtcGetScanoutSize(RRCrtcPtr crtc, int *width, int *height)
634 {
635     RRModeGetScanoutSize (crtc->mode, &crtc->transform, width, height);
636 }
637
638 /*
639  * Set the size of the gamma table at server startup time
640  */
641
642 Bool
643 RRCrtcGammaSetSize (RRCrtcPtr   crtc,
644                     int         size)
645 {
646     CARD16  *gamma;
647
648     if (size == crtc->gammaSize)
649         return TRUE;
650     if (size)
651     {
652         gamma = malloc(size * 3 * sizeof (CARD16));
653         if (!gamma)
654             return FALSE;
655     }
656     else
657         gamma = NULL;
658     free(crtc->gammaRed);
659     crtc->gammaRed = gamma;
660     crtc->gammaGreen = gamma + size;
661     crtc->gammaBlue = gamma + size*2;
662     crtc->gammaSize = size;
663     return TRUE;
664 }
665
666 /*
667  * Set the pending CRTC transformation
668  */
669
670 int
671 RRCrtcTransformSet (RRCrtcPtr           crtc,
672                     PictTransformPtr    transform,
673                     struct pixman_f_transform *f_transform,
674                     struct pixman_f_transform *f_inverse,
675                     char                *filter_name,
676                     int                 filter_len,
677                     xFixed              *params,
678                     int                 nparams)
679 {
680     PictFilterPtr   filter = NULL;
681     int             width = 0, height = 0;
682
683     if (!crtc->transforms)
684         return BadValue;
685
686     if (filter_len)
687     {
688         filter = PictureFindFilter (crtc->pScreen,
689                                     filter_name,
690                                     filter_len);
691         if (!filter)
692             return BadName;
693         if (filter->ValidateParams)
694         {
695             if (!filter->ValidateParams (crtc->pScreen, filter->id,
696                                          params, nparams, &width, &height))
697                 return BadMatch;
698         }
699         else {
700             width = filter->width;
701             height = filter->height;
702         }
703     }
704     else
705     {
706         if (nparams)
707             return BadMatch;
708     }
709     if (!RRTransformSetFilter (&crtc->client_pending_transform,
710                                filter, params, nparams, width, height))
711         return BadAlloc;
712
713     crtc->client_pending_transform.transform = *transform;
714     crtc->client_pending_transform.f_transform = *f_transform;
715     crtc->client_pending_transform.f_inverse = *f_inverse;
716     return Success;
717 }
718
719 /*
720  * Initialize crtc type
721  */
722 Bool
723 RRCrtcInit (void)
724 {
725     RRCrtcType = CreateNewResourceType (RRCrtcDestroyResource, "CRTC");
726     if (!RRCrtcType)
727         return FALSE;
728     
729     return TRUE;
730 }
731
732 /*
733  * Initialize crtc type error value
734  */
735 void
736 RRCrtcInitErrorValue(void)
737 {
738     SetResourceTypeErrorValue(RRCrtcType, RRErrorBase + BadRRCrtc);
739 }
740
741 int
742 ProcRRGetCrtcInfo (ClientPtr client)
743 {
744     REQUEST(xRRGetCrtcInfoReq);
745     xRRGetCrtcInfoReply rep;
746     RRCrtcPtr                   crtc;
747     CARD8                       *extra;
748     unsigned long               extraLen;
749     ScreenPtr                   pScreen;
750     rrScrPrivPtr                pScrPriv;
751     RRModePtr                   mode;
752     RROutput                    *outputs;
753     RROutput                    *possible;
754     int                         i, j, k;
755     int                         width, height;
756     BoxRec                      panned_area;
757     
758     REQUEST_SIZE_MATCH(xRRGetCrtcInfoReq);
759     VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
760
761     /* All crtcs must be associated with screens before client
762      * requests are processed
763      */
764     pScreen = crtc->pScreen;
765     pScrPriv = rrGetScrPriv(pScreen);
766
767     mode = crtc->mode;
768     
769     rep.type = X_Reply;
770     rep.status = RRSetConfigSuccess;
771     rep.sequenceNumber = client->sequence;
772     rep.length = 0;
773     rep.timestamp = pScrPriv->lastSetTime.milliseconds;
774     if (pScrPriv->rrGetPanning &&
775         pScrPriv->rrGetPanning (pScreen, crtc, &panned_area, NULL, NULL) &&
776         (panned_area.x2 > panned_area.x1) && (panned_area.y2 > panned_area.y1))
777     {
778         rep.x = panned_area.x1;
779         rep.y = panned_area.y1;
780         rep.width = panned_area.x2 - panned_area.x1;
781         rep.height = panned_area.y2 - panned_area.y1;
782     }
783     else
784     {
785         RRCrtcGetScanoutSize (crtc, &width, &height);
786         rep.x = crtc->x;
787         rep.y = crtc->y;
788         rep.width = width;
789         rep.height = height;
790     }
791     rep.mode = mode ? mode->mode.id : 0;
792     rep.rotation = crtc->rotation;
793     rep.rotations = crtc->rotations;
794     rep.nOutput = crtc->numOutputs;
795     k = 0;
796     for (i = 0; i < pScrPriv->numOutputs; i++)
797         for (j = 0; j < pScrPriv->outputs[i]->numCrtcs; j++)
798             if (pScrPriv->outputs[i]->crtcs[j] == crtc)
799                 k++;
800     rep.nPossibleOutput = k;
801     
802     rep.length = rep.nOutput + rep.nPossibleOutput;
803
804     extraLen = rep.length << 2;
805     if (extraLen)
806     {
807         extra = malloc(extraLen);
808         if (!extra)
809             return BadAlloc;
810     }
811     else
812         extra = NULL;
813
814     outputs = (RROutput *) extra;
815     possible = (RROutput *) (outputs + rep.nOutput);
816     
817     for (i = 0; i < crtc->numOutputs; i++)
818     {
819         outputs[i] = crtc->outputs[i]->id;
820         if (client->swapped)
821             swapl(&outputs[i]);
822     }
823     k = 0;
824     for (i = 0; i < pScrPriv->numOutputs; i++)
825         for (j = 0; j < pScrPriv->outputs[i]->numCrtcs; j++)
826             if (pScrPriv->outputs[i]->crtcs[j] == crtc)
827             {
828                 possible[k] = pScrPriv->outputs[i]->id;
829                 if (client->swapped)
830                     swapl(&possible[k]);
831                 k++;
832             }
833     
834     if (client->swapped) {
835         swaps(&rep.sequenceNumber);
836         swapl(&rep.length);
837         swapl(&rep.timestamp);
838         swaps(&rep.x);
839         swaps(&rep.y);
840         swaps(&rep.width);
841         swaps(&rep.height);
842         swapl(&rep.mode);
843         swaps(&rep.rotation);
844         swaps(&rep.rotations);
845         swaps(&rep.nOutput);
846         swaps(&rep.nPossibleOutput);
847     }
848     WriteToClient(client, sizeof(xRRGetCrtcInfoReply), (char *)&rep);
849     if (extraLen)
850     {
851         WriteToClient (client, extraLen, (char *) extra);
852         free(extra);
853     }
854     
855     return Success;
856 }
857
858 int
859 ProcRRSetCrtcConfig (ClientPtr client)
860 {
861     REQUEST(xRRSetCrtcConfigReq);
862     xRRSetCrtcConfigReply   rep;
863     ScreenPtr               pScreen;
864     rrScrPrivPtr            pScrPriv;
865     RRCrtcPtr               crtc;
866     RRModePtr               mode;
867     int                     numOutputs;
868     RROutputPtr             *outputs = NULL;
869     RROutput                *outputIds;
870     TimeStamp               configTime;
871     TimeStamp               time;
872     Rotation                rotation;
873     int                     rc, i, j;
874     
875     REQUEST_AT_LEAST_SIZE(xRRSetCrtcConfigReq);
876     numOutputs = (stuff->length - bytes_to_int32(SIZEOF (xRRSetCrtcConfigReq)));
877     
878     VERIFY_RR_CRTC(stuff->crtc, crtc, DixSetAttrAccess);
879
880     if (stuff->mode == None)
881     {
882         mode = NULL;
883         if (numOutputs > 0)
884             return BadMatch;
885     }
886     else
887     {
888         VERIFY_RR_MODE(stuff->mode, mode, DixSetAttrAccess);
889         if (numOutputs == 0)
890             return BadMatch;
891     }
892     if (numOutputs)
893     {
894         outputs = malloc(numOutputs * sizeof (RROutputPtr));
895         if (!outputs)
896             return BadAlloc;
897     }
898     else
899         outputs = NULL;
900     
901     outputIds = (RROutput *) (stuff + 1);
902     for (i = 0; i < numOutputs; i++)
903     {
904         rc = dixLookupResourceByType((pointer *)(outputs + i), outputIds[i],
905                                      RROutputType, client, DixSetAttrAccess);
906         if (rc != Success)
907         {
908             free(outputs);
909             return rc;
910         }
911         /* validate crtc for this output */
912         for (j = 0; j < outputs[i]->numCrtcs; j++)
913             if (outputs[i]->crtcs[j] == crtc)
914                 break;
915         if (j == outputs[i]->numCrtcs)
916         {
917             free(outputs);
918             return BadMatch;
919         }
920         /* validate mode for this output */
921         for (j = 0; j < outputs[i]->numModes + outputs[i]->numUserModes; j++)
922         {
923             RRModePtr   m = (j < outputs[i]->numModes ? 
924                              outputs[i]->modes[j] :
925                              outputs[i]->userModes[j - outputs[i]->numModes]);
926             if (m == mode)
927                 break;
928         }
929         if (j == outputs[i]->numModes + outputs[i]->numUserModes)
930         {
931             free(outputs);
932             return BadMatch;
933         }
934     }
935     /* validate clones */
936     for (i = 0; i < numOutputs; i++)
937     {
938         for (j = 0; j < numOutputs; j++)
939         {
940             int k;
941             if (i == j)
942                 continue;
943             for (k = 0; k < outputs[i]->numClones; k++)
944             {
945                 if (outputs[i]->clones[k] == outputs[j])
946                     break;
947             }
948             if (k == outputs[i]->numClones)
949             {
950                 free(outputs);
951                 return BadMatch;
952             }
953         }
954     }
955
956     pScreen = crtc->pScreen;
957     pScrPriv = rrGetScrPriv(pScreen);
958     
959     time = ClientTimeToServerTime(stuff->timestamp);
960     configTime = ClientTimeToServerTime(stuff->configTimestamp);
961     
962     if (!pScrPriv)
963     {
964         time = currentTime;
965         rep.status = RRSetConfigFailed;
966         goto sendReply;
967     }
968     
969     /*
970      * Validate requested rotation
971      */
972     rotation = (Rotation) stuff->rotation;
973
974     /* test the rotation bits only! */
975     switch (rotation & 0xf) {
976     case RR_Rotate_0:
977     case RR_Rotate_90:
978     case RR_Rotate_180:
979     case RR_Rotate_270:
980         break;
981     default:
982         /*
983          * Invalid rotation
984          */
985         client->errorValue = stuff->rotation;
986         free(outputs);
987         return BadValue;
988     }
989
990     if (mode)
991     {
992         if ((~crtc->rotations) & rotation)
993         {
994             /*
995              * requested rotation or reflection not supported by screen
996              */
997             client->errorValue = stuff->rotation;
998             free(outputs);
999             return BadMatch;
1000         }
1001     
1002 #ifdef RANDR_12_INTERFACE
1003         /*
1004          * Check screen size bounds if the DDX provides a 1.2 interface
1005          * for setting screen size. Else, assume the CrtcSet sets
1006          * the size along with the mode. If the driver supports transforms,
1007          * then it must allow crtcs to display a subset of the screen, so
1008          * only do this check for drivers without transform support.
1009          */
1010         if (pScrPriv->rrScreenSetSize && !crtc->transforms)
1011         {
1012             int source_width;
1013             int source_height;
1014             PictTransform transform;
1015             struct pixman_f_transform f_transform, f_inverse;
1016
1017             RRTransformCompute (stuff->x, stuff->y,
1018                                 mode->mode.width, mode->mode.height,
1019                                 rotation,
1020                                 &crtc->client_pending_transform,
1021                                 &transform, &f_transform, &f_inverse);
1022
1023             RRModeGetScanoutSize (mode, &transform, &source_width, &source_height);
1024             if (stuff->x + source_width > pScreen->width)
1025             {
1026                 client->errorValue = stuff->x;
1027                 free(outputs);
1028                 return BadValue;
1029             }
1030             
1031             if (stuff->y + source_height > pScreen->height)
1032             {
1033                 client->errorValue = stuff->y;
1034                 free(outputs);
1035                 return BadValue;
1036             }
1037         }
1038 #endif
1039     }
1040     
1041     if (!RRCrtcSet (crtc, mode, stuff->x, stuff->y,
1042                    rotation, numOutputs, outputs))
1043     {
1044         rep.status = RRSetConfigFailed;
1045         goto sendReply;
1046     }
1047     rep.status = RRSetConfigSuccess;
1048     pScrPriv->lastSetTime = time;
1049     
1050 sendReply:
1051     free(outputs);
1052     
1053     rep.type = X_Reply;
1054     /* rep.status has already been filled in */
1055     rep.length = 0;
1056     rep.sequenceNumber = client->sequence;
1057     rep.newTimestamp = pScrPriv->lastSetTime.milliseconds;
1058
1059     if (client->swapped) 
1060     {
1061         swaps(&rep.sequenceNumber);
1062         swapl(&rep.length);
1063         swapl(&rep.newTimestamp);
1064     }
1065     WriteToClient(client, sizeof(xRRSetCrtcConfigReply), (char *)&rep);
1066     
1067     return Success;
1068 }
1069
1070 int
1071 ProcRRGetPanning (ClientPtr client)
1072 {
1073     REQUEST(xRRGetPanningReq);
1074     xRRGetPanningReply  rep;
1075     RRCrtcPtr           crtc;
1076     ScreenPtr           pScreen;
1077     rrScrPrivPtr        pScrPriv;
1078     BoxRec              total;
1079     BoxRec              tracking;
1080     INT16               border[4];
1081     
1082     REQUEST_SIZE_MATCH(xRRGetPanningReq);
1083     VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
1084
1085     /* All crtcs must be associated with screens before client
1086      * requests are processed
1087      */
1088     pScreen = crtc->pScreen;
1089     pScrPriv = rrGetScrPriv(pScreen);
1090
1091     if (!pScrPriv)
1092         return RRErrorBase + BadRRCrtc;
1093
1094     memset(&rep, 0, sizeof(rep));
1095     rep.type = X_Reply;
1096     rep.status = RRSetConfigSuccess;
1097     rep.sequenceNumber = client->sequence;
1098     rep.length = 1;
1099     rep.timestamp = pScrPriv->lastSetTime.milliseconds;
1100
1101     if (pScrPriv->rrGetPanning &&
1102         pScrPriv->rrGetPanning (pScreen, crtc, &total, &tracking, border)) {
1103         rep.left          = total.x1;
1104         rep.top           = total.y1;
1105         rep.width         = total.x2 - total.x1;
1106         rep.height        = total.y2 - total.y1;
1107         rep.track_left    = tracking.x1;
1108         rep.track_top     = tracking.y1;
1109         rep.track_width   = tracking.x2 - tracking.x1;
1110         rep.track_height  = tracking.y2 - tracking.y1;
1111         rep.border_left   = border[0];
1112         rep.border_top    = border[1];
1113         rep.border_right  = border[2];
1114         rep.border_bottom = border[3];
1115     }
1116
1117     if (client->swapped) {
1118         swaps(&rep.sequenceNumber);
1119         swapl(&rep.length);
1120         swapl(&rep.timestamp);
1121         swaps(&rep.left);
1122         swaps(&rep.top);
1123         swaps(&rep.width);
1124         swaps(&rep.height);
1125         swaps(&rep.track_left);
1126         swaps(&rep.track_top);
1127         swaps(&rep.track_width);
1128         swaps(&rep.track_height);
1129         swaps(&rep.border_left);
1130         swaps(&rep.border_top);
1131         swaps(&rep.border_right);
1132         swaps(&rep.border_bottom);
1133     }
1134     WriteToClient(client, sizeof(xRRGetPanningReply), (char *)&rep);
1135     return Success;
1136 }
1137
1138 int
1139 ProcRRSetPanning (ClientPtr client)
1140 {
1141     REQUEST(xRRSetPanningReq);
1142     xRRSetPanningReply  rep;
1143     RRCrtcPtr           crtc;
1144     ScreenPtr           pScreen;
1145     rrScrPrivPtr        pScrPriv;
1146     TimeStamp           time;
1147     BoxRec              total;
1148     BoxRec              tracking;
1149     INT16               border[4];
1150     
1151     REQUEST_SIZE_MATCH(xRRSetPanningReq);
1152     VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
1153
1154     /* All crtcs must be associated with screens before client
1155      * requests are processed
1156      */
1157     pScreen = crtc->pScreen;
1158     pScrPriv = rrGetScrPriv(pScreen);
1159
1160     if (!pScrPriv) {
1161         time = currentTime;
1162         rep.status = RRSetConfigFailed;
1163         goto sendReply;
1164     }
1165     
1166     time = ClientTimeToServerTime(stuff->timestamp);
1167     
1168     if (!pScrPriv->rrGetPanning)
1169         return RRErrorBase + BadRRCrtc;
1170
1171     total.x1    = stuff->left;
1172     total.y1    = stuff->top;
1173     total.x2    = total.x1 + stuff->width;
1174     total.y2    = total.y1 + stuff->height;
1175     tracking.x1 = stuff->track_left;
1176     tracking.y1 = stuff->track_top;
1177     tracking.x2 = tracking.x1 + stuff->track_width;
1178     tracking.y2 = tracking.y1 + stuff->track_height;
1179     border[0]   = stuff->border_left;
1180     border[1]   = stuff->border_top;
1181     border[2]   = stuff->border_right;
1182     border[3]   = stuff->border_bottom;
1183
1184     if (! pScrPriv->rrSetPanning (pScreen, crtc, &total, &tracking, border))
1185         return BadMatch;
1186
1187     pScrPriv->lastSetTime = time;
1188
1189     rep.status = RRSetConfigSuccess;
1190
1191 sendReply:
1192     rep.type = X_Reply;
1193     rep.sequenceNumber = client->sequence;
1194     rep.length = 0;
1195     rep.newTimestamp = pScrPriv->lastSetTime.milliseconds;
1196
1197     if (client->swapped) {
1198         swaps(&rep.sequenceNumber);
1199         swapl(&rep.length);
1200         swapl(&rep.newTimestamp);
1201     }
1202     WriteToClient(client, sizeof(xRRSetPanningReply), (char *)&rep);
1203     return Success;
1204 }
1205
1206 int
1207 ProcRRGetCrtcGammaSize (ClientPtr client)
1208 {
1209     REQUEST(xRRGetCrtcGammaSizeReq);
1210     xRRGetCrtcGammaSizeReply    reply;
1211     RRCrtcPtr                   crtc;
1212
1213     REQUEST_SIZE_MATCH(xRRGetCrtcGammaSizeReq);
1214     VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
1215
1216     /* Gamma retrieval failed, any better error? */
1217     if (!RRCrtcGammaGet(crtc))
1218         return RRErrorBase + BadRRCrtc;
1219
1220     reply.type = X_Reply;
1221     reply.sequenceNumber = client->sequence;
1222     reply.length = 0;
1223     reply.size = crtc->gammaSize;
1224     if (client->swapped) {
1225         swaps(&reply.sequenceNumber);
1226         swapl(&reply.length);
1227         swaps(&reply.size);
1228     }
1229     WriteToClient (client, sizeof (xRRGetCrtcGammaSizeReply), (char *) &reply);
1230     return Success;
1231 }
1232
1233 int
1234 ProcRRGetCrtcGamma (ClientPtr client)
1235 {
1236     REQUEST(xRRGetCrtcGammaReq);
1237     xRRGetCrtcGammaReply        reply;
1238     RRCrtcPtr                   crtc;
1239     unsigned long               len;
1240     char                        *extra = NULL;
1241     
1242     REQUEST_SIZE_MATCH(xRRGetCrtcGammaReq);
1243     VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
1244
1245     /* Gamma retrieval failed, any better error? */
1246     if (!RRCrtcGammaGet(crtc))
1247         return RRErrorBase + BadRRCrtc;
1248
1249     len = crtc->gammaSize * 3 * 2;
1250     
1251     if (crtc->gammaSize) {
1252         extra = malloc(len);
1253         if (!extra)
1254             return BadAlloc;
1255     }
1256
1257     reply.type = X_Reply;
1258     reply.sequenceNumber = client->sequence;
1259     reply.length = bytes_to_int32(len);
1260     reply.size = crtc->gammaSize;
1261     if (client->swapped) {
1262         swaps(&reply.sequenceNumber);
1263         swapl(&reply.length);
1264         swaps(&reply.size);
1265     }
1266     WriteToClient (client, sizeof (xRRGetCrtcGammaReply), (char *) &reply);
1267     if (crtc->gammaSize)
1268     {
1269         memcpy(extra, crtc->gammaRed, len);
1270         client->pSwapReplyFunc = (ReplySwapPtr)CopySwap16Write;
1271         WriteSwappedDataToClient (client, len, extra);
1272         free(extra);
1273     }
1274     return Success;
1275 }
1276
1277 int
1278 ProcRRSetCrtcGamma (ClientPtr client)
1279 {
1280     REQUEST(xRRSetCrtcGammaReq);
1281     RRCrtcPtr                   crtc;
1282     unsigned long               len;
1283     CARD16                      *red, *green, *blue;
1284     
1285     REQUEST_AT_LEAST_SIZE(xRRSetCrtcGammaReq);
1286     VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
1287     
1288     len = client->req_len - bytes_to_int32(sizeof (xRRSetCrtcGammaReq));
1289     if (len < (stuff->size * 3 + 1) >> 1)
1290         return BadLength;
1291
1292     if (stuff->size != crtc->gammaSize)
1293         return BadMatch;
1294     
1295     red = (CARD16 *) (stuff + 1);
1296     green = red + crtc->gammaSize;
1297     blue = green + crtc->gammaSize;
1298     
1299     RRCrtcGammaSet (crtc, red, green, blue);
1300
1301     return Success;
1302 }
1303
1304 /* Version 1.3 additions */
1305
1306 int
1307 ProcRRSetCrtcTransform (ClientPtr client)
1308 {
1309     REQUEST(xRRSetCrtcTransformReq);
1310     RRCrtcPtr               crtc;
1311     PictTransform           transform;
1312     struct pixman_f_transform f_transform, f_inverse;
1313     char                    *filter;
1314     int                     nbytes;
1315     xFixed                  *params;
1316     int                     nparams;
1317
1318     REQUEST_AT_LEAST_SIZE(xRRSetCrtcTransformReq);
1319     VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
1320
1321     PictTransform_from_xRenderTransform (&transform, &stuff->transform);
1322     pixman_f_transform_from_pixman_transform (&f_transform, &transform);
1323     if (!pixman_f_transform_invert (&f_inverse, &f_transform))
1324         return BadMatch;
1325
1326     filter = (char *) (stuff + 1);
1327     nbytes = stuff->nbytesFilter;
1328     params = (xFixed *) (filter + pad_to_int32(nbytes));
1329     nparams = ((xFixed *) stuff + client->req_len) - params;
1330     if (nparams < 0)
1331         return BadLength;
1332
1333     return RRCrtcTransformSet (crtc, &transform, &f_transform, &f_inverse,
1334                                filter, nbytes, params, nparams);
1335 }
1336
1337
1338 #define CrtcTransformExtra      (SIZEOF(xRRGetCrtcTransformReply) - 32)
1339                                 
1340 static int
1341 transform_filter_length (RRTransformPtr transform)
1342 {
1343     int nbytes, nparams;
1344
1345     if (transform->filter == NULL)
1346         return 0;
1347     nbytes = strlen (transform->filter->name);
1348     nparams = transform->nparams;
1349     return pad_to_int32(nbytes) + (nparams * sizeof (xFixed));
1350 }
1351
1352 static int
1353 transform_filter_encode (ClientPtr client, char *output,
1354                          CARD16 *nbytesFilter,
1355                          CARD16 *nparamsFilter,
1356                          RRTransformPtr transform)
1357 {
1358     int     nbytes, nparams;
1359
1360     if (transform->filter == NULL) {
1361         *nbytesFilter = 0;
1362         *nparamsFilter = 0;
1363         return 0;
1364     }
1365     nbytes = strlen (transform->filter->name);
1366     nparams = transform->nparams;
1367     *nbytesFilter = nbytes;
1368     *nparamsFilter = nparams;
1369     memcpy (output, transform->filter->name, nbytes);
1370     while ((nbytes & 3) != 0)
1371         output[nbytes++] = 0;
1372     memcpy (output + nbytes, transform->params, nparams * sizeof (xFixed));
1373     if (client->swapped) {
1374         swaps(nbytesFilter);
1375         swaps(nparamsFilter);
1376         SwapLongs ((CARD32 *) (output + nbytes), nparams);
1377     }
1378     nbytes += nparams * sizeof (xFixed);
1379     return nbytes;
1380 }
1381
1382 static void
1383 transform_encode (ClientPtr client, xRenderTransform *wire, PictTransform *pict)
1384 {
1385     xRenderTransform_from_PictTransform (wire, pict);
1386     if (client->swapped)
1387         SwapLongs ((CARD32 *) wire, bytes_to_int32(sizeof(xRenderTransform)));
1388 }
1389
1390 int
1391 ProcRRGetCrtcTransform (ClientPtr client)
1392 {
1393     REQUEST(xRRGetCrtcTransformReq);
1394     xRRGetCrtcTransformReply    *reply;
1395     RRCrtcPtr                   crtc;
1396     int                         nextra;
1397     RRTransformPtr              current, pending;
1398     char                        *extra;
1399
1400     REQUEST_SIZE_MATCH (xRRGetCrtcTransformReq);
1401     VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
1402
1403     pending = &crtc->client_pending_transform;
1404     current = &crtc->client_current_transform;
1405
1406     nextra = (transform_filter_length (pending) +
1407               transform_filter_length (current));
1408
1409     reply = malloc(sizeof (xRRGetCrtcTransformReply) + nextra);
1410     if (!reply)
1411         return BadAlloc;
1412
1413     extra = (char *) (reply + 1);
1414     reply->type = X_Reply;
1415     reply->sequenceNumber = client->sequence;
1416     reply->length = bytes_to_int32(CrtcTransformExtra + nextra);
1417
1418     reply->hasTransforms = crtc->transforms;
1419
1420     transform_encode (client, &reply->pendingTransform, &pending->transform);
1421     extra += transform_filter_encode (client, extra,
1422                                       &reply->pendingNbytesFilter,
1423                                       &reply->pendingNparamsFilter,
1424                                       pending);
1425
1426     transform_encode (client, &reply->currentTransform, &current->transform);
1427     extra += transform_filter_encode (client, extra,
1428                                       &reply->currentNbytesFilter,
1429                                       &reply->currentNparamsFilter,
1430                                       current);
1431
1432     if (client->swapped) {
1433         swaps(&reply->sequenceNumber);
1434         swapl(&reply->length);
1435     }
1436     WriteToClient (client, sizeof (xRRGetCrtcTransformReply) + nextra, (char *) reply);
1437     free(reply);
1438     return Success;
1439 }
1440
1441 void
1442 RRConstrainCursorHarder(DeviceIntPtr pDev, ScreenPtr pScreen, int mode, int *x, int *y)
1443 {
1444     rrScrPriv (pScreen);
1445     int i;
1446
1447     /* intentional dead space -> let it float */
1448     if (pScrPriv->discontiguous)
1449        return;
1450
1451     /* if we're moving inside a crtc, we're fine */
1452     for (i = 0; i < pScrPriv->numCrtcs; i++) {
1453        RRCrtcPtr crtc = pScrPriv->crtcs[i];
1454
1455        int left, right, top, bottom;
1456
1457        if (!crtc->mode)
1458            continue;
1459
1460        crtc_bounds(crtc, &left, &right, &top, &bottom);
1461
1462        if ((*x >= left) && (*x <= right) && (*y >= top) && (*y <= bottom))
1463            return;
1464     }
1465
1466     /* if we're trying to escape, clamp to the CRTC we're coming from */
1467     for (i = 0; i < pScrPriv->numCrtcs; i++) {
1468        RRCrtcPtr crtc = pScrPriv->crtcs[i];
1469        int nx, ny;
1470        int left, right, top, bottom;
1471
1472        if (!crtc->mode)
1473            continue;
1474
1475        crtc_bounds(crtc, &left, &right, &top, &bottom);
1476        miPointerGetPosition(pDev, &nx, &ny);
1477
1478        if ((nx >= left) && (nx <= right) && (ny >= top) && (ny <= bottom)) {
1479            if ((*x <= left) || (*x >= right)) {
1480                int dx = *x - nx;
1481
1482                if (dx > 0)
1483                    *x = right;
1484                else if (dx < 0)
1485                    *x = left;
1486            }
1487
1488            if ((*y <= top) || (*y >= bottom)) {
1489                int dy = *y - ny;
1490
1491                if (dy > 0)
1492                    *y = bottom;
1493                else if (dy < 0)
1494                    *y = top;
1495            }
1496
1497            return;
1498        }
1499     }
1500 }