initial commit
[profile/ivi/xorg-x11-server.git] / hw / xfree86 / modes / xf86RandR12.c
1 /*
2  * Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc.
3  *
4  * Permission to use, copy, modify, distribute, and sell this software and its
5  * documentation for any purpose is hereby granted without fee, provided that
6  * the above copyright notice appear in all copies and that both that copyright
7  * notice and this permission notice appear in supporting documentation, and
8  * that the name of the copyright holders not be used in advertising or
9  * publicity pertaining to distribution of the software without specific,
10  * written prior permission.  The copyright holders make no representations
11  * about the suitability of this software for any purpose.  It is provided "as
12  * is" without express or implied warranty.
13  *
14  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20  * OF THIS SOFTWARE.
21  */
22
23 #ifdef HAVE_XORG_CONFIG_H
24 #include <xorg-config.h>
25 #else
26 #ifdef HAVE_CONFIG_H
27 #include <config.h>
28 #endif
29 #endif
30
31 #include "xf86.h"
32 #include "os.h"
33 #include "globals.h"
34 #include "xf86.h"
35 #include "xf86Priv.h"
36 #include "xf86DDC.h"
37 #include "mipointer.h"
38 #include "windowstr.h"
39 #include "inputstr.h"
40 #include <randrstr.h>
41 #include <X11/extensions/render.h>
42
43 #include "xf86Crtc.h"
44 #include "xf86RandR12.h"
45
46 typedef struct _xf86RandR12Info {
47     int                             virtualX;
48     int                             virtualY;
49     int                             mmWidth;
50     int                             mmHeight;
51     int                             maxX;
52     int                             maxY;
53     int                             pointerX;
54     int                             pointerY;
55     Rotation                        rotation; /* current mode */
56     Rotation                        supported_rotations; /* driver supported */
57
58     /* Used to wrap EnterVT so we can re-probe the outputs when a laptop unsuspends
59      * (actually, any time that we switch back into our VT).
60      *
61      * See https://bugs.freedesktop.org/show_bug.cgi?id=21554
62      */
63     xf86EnterVTProc *orig_EnterVT;
64 } XF86RandRInfoRec, *XF86RandRInfoPtr;
65
66 #ifdef RANDR_12_INTERFACE
67 static Bool xf86RandR12Init12 (ScreenPtr pScreen);
68 static Bool xf86RandR12CreateScreenResources12 (ScreenPtr pScreen);
69 #endif
70
71 static int xf86RandR12Generation;
72 #if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(7,0,0,0,0)
73
74 static DevPrivateKeyRec xf86RandR12KeyRec;
75 static DevPrivateKey xf86RandR12Key;
76 #define XF86RANDRINFO(p) ((XF86RandRInfoPtr) \
77     dixLookupPrivate(&(p)->devPrivates, xf86RandR12Key))
78
79 #else /* XORG_VERSION_CURRENT < 7.0 */
80
81 static int xf86RandR12Index;
82 #define XF86RANDRINFO(p) \
83     ((XF86RandRInfoPtr)(p)->devPrivates[xf86RandR12Index].ptr)
84
85 #endif /* XORG_VERSION_CURRENT < 7.0 */
86
87
88 static int
89 xf86RandR12ModeRefresh (DisplayModePtr mode)
90 {
91     if (mode->VRefresh)
92         return (int) (mode->VRefresh + 0.5);
93     else
94         return (int) (mode->Clock * 1000.0 / mode->HTotal / mode->VTotal + 0.5);
95 }
96
97 /* Adapt panning area; return TRUE if panning area was valid without adaption */
98 static int
99 xf86RandR13VerifyPanningArea (xf86CrtcPtr crtc, int screenWidth, int screenHeight)
100 {
101     int ret = TRUE;
102
103     if (crtc->version < 2)
104         return FALSE;
105
106     if (crtc->panningTotalArea.x2 <= crtc->panningTotalArea.x1) {
107         /* Panning in X is disabled */
108         if (crtc->panningTotalArea.x1 || crtc->panningTotalArea.x2)
109             /* Illegal configuration -> fail/disable */
110             ret = FALSE;
111         crtc->panningTotalArea.x1    = crtc->panningTotalArea.x2    = 0;
112         crtc->panningTrackingArea.x1 = crtc->panningTrackingArea.x2 = 0;
113         crtc->panningBorder[0]       = crtc->panningBorder[2]       = 0;
114     } else {
115         /* Panning in X is enabled */
116         if (crtc->panningTotalArea.x1 < 0) {
117             /* Panning region outside screen -> move inside */
118             crtc->panningTotalArea.x2 -= crtc->panningTotalArea.x1;
119             crtc->panningTotalArea.x1 = 0;
120             ret = FALSE;
121         }
122         if (crtc->panningTotalArea.x2 < crtc->panningTotalArea.x1 + crtc->mode.HDisplay) {
123             /* Panning region smaller than displayed area -> crop to displayed area */
124             crtc->panningTotalArea.x2 = crtc->panningTotalArea.x1 + crtc->mode.HDisplay;
125             ret = FALSE;
126         }
127         if (crtc->panningTotalArea.x2 > screenWidth) {
128             /* Panning region larger than screen -> move inside, then crop to screen */
129             crtc->panningTotalArea.x1 -= crtc->panningTotalArea.x2 - screenWidth;
130             crtc->panningTotalArea.x2 = screenWidth;
131             ret = FALSE;
132             if (crtc->panningTotalArea.x1 < 0)
133                 crtc->panningTotalArea.x1 = 0;
134         }
135         if (crtc->panningBorder[0] + crtc->panningBorder[2] > crtc->mode.HDisplay) {
136             /* Borders too large -> set to 0 */
137             crtc->panningBorder[0] = crtc->panningBorder[2] = 0;
138             ret = FALSE;
139         }
140     }
141
142     if (crtc->panningTotalArea.y2 <= crtc->panningTotalArea.y1) {
143         /* Panning in Y is disabled */
144         if (crtc->panningTotalArea.y1 || crtc->panningTotalArea.y2)
145             /* Illegal configuration -> fail/disable */
146             ret = FALSE;
147         crtc->panningTotalArea.y1    = crtc->panningTotalArea.y2    = 0;
148         crtc->panningTrackingArea.y1 = crtc->panningTrackingArea.y2 = 0;
149         crtc->panningBorder[1]       = crtc->panningBorder[3]       = 0;
150     } else {
151         /* Panning in Y is enabled */
152         if (crtc->panningTotalArea.y1 < 0) {
153             /* Panning region outside screen -> move inside */
154             crtc->panningTotalArea.y2 -= crtc->panningTotalArea.y1;
155             crtc->panningTotalArea.y1 = 0;
156             ret = FALSE;
157         }
158         if (crtc->panningTotalArea.y2 < crtc->panningTotalArea.y1 + crtc->mode.VDisplay) {
159             /* Panning region smaller than displayed area -> crop to displayed area */
160             crtc->panningTotalArea.y2 = crtc->panningTotalArea.y1 + crtc->mode.VDisplay;
161             ret = FALSE;
162         }
163         if (crtc->panningTotalArea.y2 > screenHeight) {
164             /* Panning region larger than screen -> move inside, then crop to screen */
165             crtc->panningTotalArea.y1 -= crtc->panningTotalArea.y2 - screenHeight;
166             crtc->panningTotalArea.y2 = screenHeight;
167             ret = FALSE;
168             if (crtc->panningTotalArea.y1 < 0)
169                 crtc->panningTotalArea.y1 = 0;
170         }
171         if (crtc->panningBorder[1] + crtc->panningBorder[3] > crtc->mode.VDisplay) {
172             /* Borders too large -> set to 0 */
173             crtc->panningBorder[1] = crtc->panningBorder[3] = 0;
174             ret = FALSE;
175         }
176     }
177
178     return ret;
179 }
180
181 /*
182  * The heart of the panning operation:
183  *
184  * Given a frame buffer position (fb_x, fb_y),
185  * and a crtc position (crtc_x, crtc_y),
186  * and a transform matrix which maps frame buffer to crtc,
187  * compute a panning position (pan_x, pan_y) that
188  * makes the resulting transform line those two up
189  */
190
191 static void
192 xf86ComputeCrtcPan (Bool transform_in_use,
193                     struct pixman_f_transform *m,
194                     double screen_x, double screen_y,
195                     double crtc_x, double crtc_y,
196                     int old_pan_x, int old_pan_y,
197                     int *new_pan_x, int *new_pan_y)
198 {
199     if (transform_in_use) {
200         /*
201          * Given the current transform, M, the current position
202          * on the Screen, S, and the desired position on the CRTC,
203          * C, compute a translation, T, such that:
204          *
205          * M T S = C
206          *
207          * where T is of the form
208          *
209          * | 1 0 dx |
210          * | 0 1 dy |
211          * | 0 0 1  |
212          *
213          * M T S =
214          *   | M00 Sx + M01 Sy + M00 dx + M01 dy + M02 |   | Cx F |
215          *   | M10 Sx + M11 Sy + M10 dx + M11 dy + M12 | = | Cy F |
216          *   | M20 Sx + M21 Sy + M20 dx + M21 dy + M22 |   |  F   |
217          *
218          * R = M S
219          *
220          *   Cx F = M00 dx + M01 dy + R0
221          *   Cy F = M10 dx + M11 dy + R1
222          *      F = M20 dx + M21 dy + R2
223          *
224          * Zero out dx, then dy
225          *
226          * F (Cx M10 - Cy M00) =
227          *          (M10 M01 - M00 M11) dy + M10 R0 - M00 R1
228          * F (M10 - Cy M20) =
229          *          (M10 M21 - M20 M11) dy + M10 R2 - M20 R1
230          *
231          * F (Cx M11 - Cy M01) =
232          *          (M11 M00 - M01 M10) dx + M11 R0 - M01 R1
233          * F (M11 - Cy M21) =
234          *          (M11 M20 - M21 M10) dx + M11 R2 - M21 R1
235          *
236          * Make some temporaries
237          *
238          * T = | Cx M10 - Cy M00 |
239          *     | Cx M11 - Cy M01 |
240          *
241          * U = | M10 M01 - M00 M11 |
242          *     | M11 M00 - M01 M10 |
243          *
244          * Q = | M10 R0 - M00 R1 |
245          *     | M11 R0 - M01 R1 |
246          *
247          * P = | M10 - Cy M20 |
248          *     | M11 - Cy M21 |
249          *
250          * W = | M10 M21 - M20 M11 |
251          *     | M11 M20 - M21 M10 |
252          *
253          * V = | M10 R2 - M20 R1 |
254          *         | M11 R2 - M21 R1 |
255          *
256          * Rewrite:
257          *
258          * F T0 = U0 dy + Q0
259          * F P0 = W0 dy + V0
260          * F T1 = U1 dx + Q1
261          * F P1 = W1 dx + V1
262          *
263          * Solve for F (two ways)
264          *
265          * F (W0 T0 - U0 P0)  = W0 Q0 - U0 V0
266          *
267          *     W0 Q0 - U0 V0
268          * F = -------------
269          *     W0 T0 - U0 P0
270          *
271          * F (W1 T1 - U1 P1) = W1 Q1 - U1 V1
272          *
273          *     W1 Q1 - U1 V1
274          * F = -------------
275          *     W1 T1 - U1 P1
276          *
277          * We'll use which ever solution works (denominator != 0)
278          *
279          * Finally, solve for dx and dy:
280          *
281          * dx = (F T1 - Q1) / U1
282          * dx = (F P1 - V1) / W1
283          *
284          * dy = (F T0 - Q0) / U0
285          * dy = (F P0 - V0) / W0
286          */
287         double                      r[3];
288         double                      q[2], u[2], t[2], v[2], w[2], p[2];
289         double                      f;
290         struct pict_f_vector        d;
291         int                         i;
292
293         /* Get the un-normalized crtc coordinates again */
294         for (i = 0; i < 3; i++)
295             r[i] = m->m[i][0] * screen_x + m->m[i][1] * screen_y + m->m[i][2];
296
297         /* Combine values into temporaries */
298         for (i = 0; i < 2; i++) {
299             q[i] = m->m[1][i] * r[0] - m->m[0][i] * r[1];
300             u[i] = m->m[1][i] * m->m[0][1-i] - m->m[0][i] * m->m[1][1-i];
301             t[i] = m->m[1][i] * crtc_x - m->m[0][i] * crtc_y;
302
303             v[i] = m->m[1][i] * r[2] - m->m[2][i] * r[1];
304             w[i] = m->m[1][i] * m->m[2][1-i] - m->m[2][i] * m->m[1][1-i];
305             p[i] = m->m[1][i] - m->m[2][i] * crtc_y;
306         }
307
308         /* Find a way to compute f */
309         f = 0;
310         for (i = 0; i < 2; i++) {
311             double a = w[i] * q[i] - u[i] * v[i];
312             double b = w[i] * t[i] - u[i] * p[i];
313             if (b != 0) {
314                 f = a/b;
315                 break;
316             }
317         }
318
319         /* Solve for the resulting transform vector */
320         for (i = 0; i < 2; i++) {
321             if (u[i])
322                 d.v[1-i] = (t[i] * f - q[i]) / u[i];
323             else if (w[1])
324                 d.v[1-i] = (p[i] * f - v[i]) / w[i];
325             else
326                 d.v[1-i] = 0;
327         }
328         *new_pan_x = old_pan_x - floor (d.v[0] + 0.5);
329         *new_pan_y = old_pan_y - floor (d.v[1] + 0.5);
330     } else {
331         *new_pan_x = screen_x - crtc_x;
332         *new_pan_y = screen_y - crtc_y;
333     }
334 }
335
336 static void
337 xf86RandR13Pan (xf86CrtcPtr crtc, int x, int y)
338 {
339     int newX, newY;
340     int width, height;
341     Bool panned = FALSE;
342
343     if (crtc->version < 2)
344         return;
345
346     if (! crtc->enabled                                         ||
347         (crtc->panningTotalArea.x2 <= crtc->panningTotalArea.x1 &&
348          crtc->panningTotalArea.y2 <= crtc->panningTotalArea.y1))
349         return;
350
351     newX   = crtc->x;
352     newY   = crtc->y;
353     width  = crtc->mode.HDisplay;
354     height = crtc->mode.VDisplay;
355
356     if ((crtc->panningTrackingArea.x2 <= crtc->panningTrackingArea.x1 ||
357          (x >= crtc->panningTrackingArea.x1 && x < crtc->panningTrackingArea.x2)) &&
358         (crtc->panningTrackingArea.y2 <= crtc->panningTrackingArea.y1 ||
359          (y >= crtc->panningTrackingArea.y1 && y < crtc->panningTrackingArea.y2)))
360     {
361         struct pict_f_vector    c;
362
363         /*
364          * Pre-clip the mouse position to the panning area so that we don't
365          * push the crtc outside. This doesn't deal with changes to the
366          * panning values, only mouse position changes.
367          */
368         if (crtc->panningTotalArea.x2 > crtc->panningTotalArea.x1)
369         {
370             if (x < crtc->panningTotalArea.x1)
371                 x = crtc->panningTotalArea.x1;
372             if (x >= crtc->panningTotalArea.x2)
373                 x = crtc->panningTotalArea.x2 - 1;
374         }
375         if (crtc->panningTotalArea.y2 > crtc->panningTotalArea.y1)
376         {
377             if (y < crtc->panningTotalArea.y1)
378                 y = crtc->panningTotalArea.y1;
379             if (y >= crtc->panningTotalArea.y2)
380                 y = crtc->panningTotalArea.y2 - 1;
381         }
382
383         c.v[0] = x;
384         c.v[1] = y;
385         c.v[2] = 1.0;
386         if (crtc->transform_in_use) {
387             pixman_f_transform_point(&crtc->f_framebuffer_to_crtc, &c);
388         } else {
389             c.v[0] -= crtc->x;
390             c.v[1] -= crtc->y;
391         }
392
393         if (crtc->panningTotalArea.x2 > crtc->panningTotalArea.x1) {
394             if (c.v[0] < crtc->panningBorder[0]) {
395                 c.v[0] = crtc->panningBorder[0];
396                 panned = TRUE;
397             }
398             if (c.v[0] >= width - crtc->panningBorder[2]) {
399                 c.v[0] = width - crtc->panningBorder[2] - 1;
400                 panned = TRUE;
401             }
402         }
403         if (crtc->panningTotalArea.y2 > crtc->panningTotalArea.y1) {
404             if (c.v[1] < crtc->panningBorder[1]) {
405                 c.v[1] = crtc->panningBorder[1];
406                 panned = TRUE;
407             }
408             if (c.v[1] >= height - crtc->panningBorder[3]) {
409                 c.v[1] = height - crtc->panningBorder[3] - 1;
410                 panned = TRUE;
411             }
412         }
413         if (panned)
414             xf86ComputeCrtcPan (crtc->transform_in_use,
415                                 &crtc->f_framebuffer_to_crtc,
416                                 x, y, c.v[0], c.v[1],
417                                 newX, newY, &newX, &newY);
418     }
419
420     /*
421      * Ensure that the crtc is within the panning region.
422      *
423      * XXX This computation only works when we do not have a transform
424      * in use.
425      */
426     if (!crtc->transform_in_use)
427     {
428         /* Validate against [xy]1 after [xy]2, to be sure that results are > 0 for [xy]1 > 0 */
429         if (crtc->panningTotalArea.x2 > crtc->panningTotalArea.x1) {
430             if (newX > crtc->panningTotalArea.x2 - width)
431                 newX =  crtc->panningTotalArea.x2 - width;
432             if (newX <  crtc->panningTotalArea.x1)
433                 newX =  crtc->panningTotalArea.x1;
434         }
435         if (crtc->panningTotalArea.y2 > crtc->panningTotalArea.y1) {
436             if (newY > crtc->panningTotalArea.y2 - height)
437                 newY =  crtc->panningTotalArea.y2 - height;
438             if (newY <  crtc->panningTotalArea.y1)
439                 newY =  crtc->panningTotalArea.y1;
440         }
441     }
442     if (newX != crtc->x || newY != crtc->y)
443         xf86CrtcSetOrigin (crtc, newX, newY);
444 }
445
446 static Bool
447 xf86RandR12GetInfo (ScreenPtr pScreen, Rotation *rotations)
448 {
449     RRScreenSizePtr         pSize;
450     ScrnInfoPtr             scrp = XF86SCRNINFO(pScreen);
451     XF86RandRInfoPtr        randrp = XF86RANDRINFO(pScreen);
452     DisplayModePtr          mode;
453     int                     refresh0 = 60;
454     int                     maxX = 0, maxY = 0;
455
456     *rotations = randrp->supported_rotations;
457
458     if (randrp->virtualX == -1 || randrp->virtualY == -1)
459     {
460         randrp->virtualX = scrp->virtualX;
461         randrp->virtualY = scrp->virtualY;
462     }
463
464     /* Re-probe the outputs for new monitors or modes */
465     if (scrp->vtSema)
466     {
467         xf86ProbeOutputModes (scrp, 0, 0);
468         xf86SetScrnInfoModes (scrp);
469     }
470
471     for (mode = scrp->modes; ; mode = mode->next)
472     {
473         int refresh = xf86RandR12ModeRefresh (mode);
474         if (randrp->maxX == 0 || randrp->maxY == 0)
475         {
476                 if (maxX < mode->HDisplay)
477                         maxX = mode->HDisplay;
478                 if (maxY < mode->VDisplay)
479                         maxY = mode->VDisplay;
480         }
481         if (mode == scrp->modes)
482             refresh0 = refresh;
483         pSize = RRRegisterSize (pScreen,
484                                 mode->HDisplay, mode->VDisplay,
485                                 randrp->mmWidth, randrp->mmHeight);
486         if (!pSize)
487             return FALSE;
488         RRRegisterRate (pScreen, pSize, refresh);
489
490         if (xf86ModesEqual(mode, scrp->currentMode))
491         {
492             RRSetCurrentConfig (pScreen, randrp->rotation, refresh, pSize);
493         }
494         if (mode->next == scrp->modes)
495             break;
496     }
497
498     if (randrp->maxX == 0 || randrp->maxY == 0)
499     {
500         randrp->maxX = maxX;
501         randrp->maxY = maxY;
502     }
503
504     return TRUE;
505 }
506
507 static Bool
508 xf86RandR12SetMode (ScreenPtr       pScreen,
509                   DisplayModePtr    mode,
510                   Bool              useVirtual,
511                   int               mmWidth,
512                   int               mmHeight)
513 {
514     ScrnInfoPtr         scrp = XF86SCRNINFO(pScreen);
515     XF86RandRInfoPtr    randrp = XF86RANDRINFO(pScreen);
516     int                 oldWidth = pScreen->width;
517     int                 oldHeight = pScreen->height;
518     int                 oldmmWidth = pScreen->mmWidth;
519     int                 oldmmHeight = pScreen->mmHeight;
520     WindowPtr           pRoot = pScreen->root;
521     DisplayModePtr      currentMode = NULL;
522     Bool                ret = TRUE;
523     PixmapPtr           pspix = NULL;
524
525     if (pRoot)
526         (*scrp->EnableDisableFBAccess) (pScreen->myNum, FALSE);
527     if (useVirtual)
528     {
529         scrp->virtualX = randrp->virtualX;
530         scrp->virtualY = randrp->virtualY;
531     }
532     else
533     {
534         scrp->virtualX = mode->HDisplay;
535         scrp->virtualY = mode->VDisplay;
536     }
537
538     if(randrp->rotation & (RR_Rotate_90 | RR_Rotate_270))
539     {
540         /* If the screen is rotated 90 or 270 degrees, swap the sizes. */
541         pScreen->width = scrp->virtualY;
542         pScreen->height = scrp->virtualX;
543         pScreen->mmWidth = mmHeight;
544         pScreen->mmHeight = mmWidth;
545     }
546     else
547     {
548         pScreen->width = scrp->virtualX;
549         pScreen->height = scrp->virtualY;
550         pScreen->mmWidth = mmWidth;
551         pScreen->mmHeight = mmHeight;
552     }
553     if (scrp->currentMode == mode) {
554         /* Save current mode */
555         currentMode = scrp->currentMode;
556         /* Reset, just so we ensure the drivers SwitchMode is called */
557         scrp->currentMode = NULL;
558     }
559     /*
560      * We know that if the driver failed to SwitchMode to the rotated
561      * version, then it should revert back to it's prior mode.
562      */
563     if (!xf86SwitchMode (pScreen, mode))
564     {
565         ret = FALSE;
566         scrp->virtualX = pScreen->width = oldWidth;
567         scrp->virtualY = pScreen->height = oldHeight;
568         pScreen->mmWidth = oldmmWidth;
569         pScreen->mmHeight = oldmmHeight;
570         scrp->currentMode = currentMode;
571     }
572     /*
573      * Get the new Screen pixmap ptr as SwitchMode might have called
574      * ModifyPixmapHeader and xf86EnableDisableFBAccess will put it back...
575      * Unfortunately.
576      */
577     pspix = (*pScreen->GetScreenPixmap) (pScreen);
578     if (pspix->devPrivate.ptr)
579        scrp->pixmapPrivate = pspix->devPrivate;
580
581     /*
582      * Make sure the layout is correct
583      */
584     xf86ReconfigureLayout();
585
586     /*
587      * Make sure the whole screen is visible
588      */
589     xf86SetViewport (pScreen, pScreen->width, pScreen->height);
590     xf86SetViewport (pScreen, 0, 0);
591     if (pRoot)
592         (*scrp->EnableDisableFBAccess) (pScreen->myNum, TRUE);
593     return ret;
594 }
595
596 Bool
597 xf86RandR12SetConfig (ScreenPtr         pScreen,
598                     Rotation            rotation,
599                     int                 rate,
600                     RRScreenSizePtr     pSize)
601 {
602     ScrnInfoPtr         scrp = XF86SCRNINFO(pScreen);
603     XF86RandRInfoPtr    randrp = XF86RANDRINFO(pScreen);
604     DisplayModePtr      mode;
605     int                 px, py;
606     Bool                useVirtual = FALSE;
607     int                 maxX = 0, maxY = 0;
608     Rotation            oldRotation = randrp->rotation;
609
610     randrp->rotation = rotation;
611
612     if (randrp->virtualX == -1 || randrp->virtualY == -1)
613     {
614         randrp->virtualX = scrp->virtualX;
615         randrp->virtualY = scrp->virtualY;
616     }
617
618     miPointerGetPosition (inputInfo.pointer, &px, &py);
619     for (mode = scrp->modes; ; mode = mode->next)
620     {
621         if (randrp->maxX == 0 || randrp->maxY == 0)
622         {
623                 if (maxX < mode->HDisplay)
624                         maxX = mode->HDisplay;
625                 if (maxY < mode->VDisplay)
626                         maxY = mode->VDisplay;
627         }
628         if (mode->HDisplay == pSize->width &&
629             mode->VDisplay == pSize->height &&
630             (rate == 0 || xf86RandR12ModeRefresh (mode) == rate))
631             break;
632         if (mode->next == scrp->modes)
633         {
634             if (pSize->width == randrp->virtualX &&
635                 pSize->height == randrp->virtualY)
636             {
637                 mode = scrp->modes;
638                 useVirtual = TRUE;
639                 break;
640             }
641             if (randrp->maxX == 0 || randrp->maxY == 0)
642             {
643                 randrp->maxX = maxX;
644                 randrp->maxY = maxY;
645             }
646             return FALSE;
647         }
648     }
649
650     if (randrp->maxX == 0 || randrp->maxY == 0)
651     {
652         randrp->maxX = maxX;
653         randrp->maxY = maxY;
654     }
655
656     if (!xf86RandR12SetMode (pScreen, mode, useVirtual, pSize->mmWidth,
657                            pSize->mmHeight)) {
658         randrp->rotation = oldRotation;
659         return FALSE;
660     }
661
662     /*
663      * Move the cursor back where it belongs; SwitchMode repositions it
664      */
665     if (pScreen == miPointerGetScreen(inputInfo.pointer))
666     {
667         px = (px >= pScreen->width ? (pScreen->width - 1) : px);
668         py = (py >= pScreen->height ? (pScreen->height - 1) : py);
669
670         xf86SetViewport(pScreen, px, py);
671
672         (*pScreen->SetCursorPosition) (inputInfo.pointer, pScreen, px, py, FALSE);
673     }
674
675     return TRUE;
676 }
677
678 static Bool
679 xf86RandR12ScreenSetSize (ScreenPtr     pScreen,
680                         CARD16          width,
681                         CARD16          height,
682                         CARD32          mmWidth,
683                         CARD32          mmHeight)
684 {
685     XF86RandRInfoPtr    randrp = XF86RANDRINFO(pScreen);
686     ScrnInfoPtr         pScrn = XF86SCRNINFO(pScreen);
687     xf86CrtcConfigPtr   config = XF86_CRTC_CONFIG_PTR(pScrn);
688     WindowPtr           pRoot = pScreen->root;
689     PixmapPtr           pScrnPix;
690     Bool                ret = FALSE;
691     int                 c;
692
693 #if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(7,0,0,0,0)
694     if (xf86RandR12Key) {
695 #endif
696         if (randrp->virtualX == -1 || randrp->virtualY == -1)
697         {
698             randrp->virtualX = pScrn->virtualX;
699             randrp->virtualY = pScrn->virtualY;
700         }
701 #if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(7,0,0,0,0)
702     }
703 #endif
704     if (pRoot && pScrn->vtSema)
705         (*pScrn->EnableDisableFBAccess) (pScreen->myNum, FALSE);
706
707     /* Let the driver update virtualX and virtualY */
708     if (!(*config->funcs->resize)(pScrn, width, height))
709         goto finish;
710
711     ret = TRUE;
712     /* Update panning information */
713     for (c = 0; c < config->num_crtc; c++) {
714         xf86CrtcPtr crtc = config->crtc[c];
715         if (crtc->panningTotalArea.x2 > crtc->panningTotalArea.x1 ||
716             crtc->panningTotalArea.y2 > crtc->panningTotalArea.y1) {
717             if (crtc->panningTotalArea.x2 > crtc->panningTrackingArea.x1)
718                 crtc->panningTotalArea.x2 += width  - pScreen->width;
719             if (crtc->panningTotalArea.y2 > crtc->panningTrackingArea.y1)
720                 crtc->panningTotalArea.y2 += height - pScreen->height;
721             if (crtc->panningTrackingArea.x2 > crtc->panningTrackingArea.x1)
722                 crtc->panningTrackingArea.x2 += width  - pScreen->width;
723             if (crtc->panningTrackingArea.y2 > crtc->panningTrackingArea.y1)
724                 crtc->panningTrackingArea.y2 += height - pScreen->height;
725             xf86RandR13VerifyPanningArea (crtc, width, height);
726             xf86RandR13Pan (crtc, randrp->pointerX, randrp->pointerY);
727         }
728     }
729
730     pScrnPix = (*pScreen->GetScreenPixmap)(pScreen);
731     pScreen->width = pScrnPix->drawable.width = width;
732     pScreen->height = pScrnPix->drawable.height = height;
733     randrp->mmWidth = pScreen->mmWidth = mmWidth;
734     randrp->mmHeight = pScreen->mmHeight = mmHeight;
735
736     xf86SetViewport (pScreen, pScreen->width-1, pScreen->height-1);
737     xf86SetViewport (pScreen, 0, 0);
738
739 finish:
740     if (pRoot && pScrn->vtSema)
741         (*pScrn->EnableDisableFBAccess) (pScreen->myNum, TRUE);
742 #if RANDR_12_INTERFACE
743     if (xf86RandR12Key && pScreen->root && ret)
744         RRScreenSizeNotify (pScreen);
745 #endif
746     return ret;
747 }
748
749 Rotation
750 xf86RandR12GetRotation(ScreenPtr pScreen)
751 {
752     XF86RandRInfoPtr        randrp = XF86RANDRINFO(pScreen);
753
754     return randrp->rotation;
755 }
756
757 Bool
758 xf86RandR12CreateScreenResources (ScreenPtr pScreen)
759 {
760     ScrnInfoPtr         pScrn = xf86Screens[pScreen->myNum];
761     xf86CrtcConfigPtr   config;
762     XF86RandRInfoPtr    randrp;
763     int                 c;
764     int                 width, height;
765     int                 mmWidth, mmHeight;
766 #ifdef PANORAMIX
767     /* XXX disable RandR when using Xinerama */
768     if (!noPanoramiXExtension)
769         return TRUE;
770 #endif
771
772     config = XF86_CRTC_CONFIG_PTR(pScrn);
773     randrp = XF86RANDRINFO(pScreen);
774     /*
775      * Compute size of screen
776      */
777     width = 0; height = 0;
778     for (c = 0; c < config->num_crtc; c++)
779     {
780         xf86CrtcPtr crtc = config->crtc[c];
781         int         crtc_width = crtc->x + xf86ModeWidth (&crtc->mode, crtc->rotation);
782         int         crtc_height = crtc->y + xf86ModeHeight (&crtc->mode, crtc->rotation);
783         
784         if (crtc->enabled) {
785             if (crtc_width > width)
786                 width = crtc_width;
787             if (crtc_height > height)
788                 height = crtc_height;
789             if (crtc->panningTotalArea.x2 > width)
790                 width = crtc->panningTotalArea.x2;
791             if (crtc->panningTotalArea.y2 > height)
792                 height = crtc->panningTotalArea.y2;
793         }
794     }
795     
796     if (width && height)
797     {
798         /*
799          * Compute physical size of screen
800          */
801         if (monitorResolution) 
802         {
803             mmWidth = width * 25.4 / monitorResolution;
804             mmHeight = height * 25.4 / monitorResolution;
805         }
806         else
807         {
808             xf86OutputPtr   output = xf86CompatOutput(pScrn);
809
810             if (output &&
811                 output->conf_monitor &&
812                 (output->conf_monitor->mon_width  > 0 &&
813                  output->conf_monitor->mon_height > 0))
814             {
815                 /*
816                  * Prefer user configured DisplaySize
817                  */
818                 mmWidth = output->conf_monitor->mon_width;
819                 mmHeight = output->conf_monitor->mon_height;
820             }
821             else
822             {
823                 /*
824                  * Otherwise, just set the screen to DEFAULT_DPI
825                  */
826                 mmWidth = width * 25.4 / DEFAULT_DPI;
827                 mmHeight = height * 25.4 / DEFAULT_DPI;
828             }
829         }
830         xf86DrvMsg(pScrn->scrnIndex, X_INFO,
831                    "Setting screen physical size to %d x %d\n",
832                    mmWidth, mmHeight);
833         /*
834          * This is the initial setting of the screen size.
835          * We have to pre-set it here, otherwise panning would be adapted
836          * to the new screen size.
837          */
838         pScreen->width  = width;
839         pScreen->height = height;
840         xf86RandR12ScreenSetSize (pScreen,
841                                   width,
842                                   height,
843                                   mmWidth,
844                                   mmHeight);
845     }
846
847 #if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(7,0,0,0,0)
848     if (xf86RandR12Key == NULL)
849         return TRUE;
850 #endif
851
852     if (randrp->virtualX == -1 || randrp->virtualY == -1)
853     {
854         randrp->virtualX = pScrn->virtualX;
855         randrp->virtualY = pScrn->virtualY;
856     }
857     xf86CrtcSetScreenSubpixelOrder (pScreen);
858 #if RANDR_12_INTERFACE
859     if (xf86RandR12CreateScreenResources12 (pScreen))
860         return TRUE;
861 #endif
862     return TRUE;
863 }
864
865
866 Bool
867 xf86RandR12Init (ScreenPtr pScreen)
868 {
869     rrScrPrivPtr        rp;
870     XF86RandRInfoPtr    randrp;
871
872 #ifdef PANORAMIX
873     /* XXX disable RandR when using Xinerama */
874     if (!noPanoramiXExtension)
875     {
876         if (xf86NumScreens == 1)
877             noPanoramiXExtension = TRUE;
878         else
879             return TRUE;
880     }
881 #endif
882
883     if (xf86RandR12Generation != serverGeneration)
884         xf86RandR12Generation = serverGeneration;
885
886 #if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(7,0,0,0,0)
887     xf86RandR12Key = &xf86RandR12KeyRec;
888     if (!dixRegisterPrivateKey(&xf86RandR12KeyRec, PRIVATE_SCREEN, 0))
889         return FALSE;
890 #else
891     xf86RandR12Index = AllocateScreenPrivateIndex();
892 #endif
893
894     randrp = malloc(sizeof (XF86RandRInfoRec));
895     if (!randrp)
896         return FALSE;
897
898     if (!RRScreenInit(pScreen))
899     {
900         free(randrp);
901         return FALSE;
902     }
903     rp = rrGetScrPriv(pScreen);
904     rp->rrGetInfo = xf86RandR12GetInfo;
905     rp->rrSetConfig = xf86RandR12SetConfig;
906
907     randrp->virtualX = -1;
908     randrp->virtualY = -1;
909     randrp->mmWidth = pScreen->mmWidth;
910     randrp->mmHeight = pScreen->mmHeight;
911
912     randrp->rotation = RR_Rotate_0; /* initial rotated mode */
913
914     randrp->supported_rotations = RR_Rotate_0;
915
916     randrp->maxX = randrp->maxY = 0;
917
918 #if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(7,0,0,0,0)
919     dixSetPrivate(&pScreen->devPrivates, xf86RandR12Key, randrp);
920 #else
921     pScreen->devPrivates[xf86RandR12Index].ptr = randrp;
922 #endif
923
924 #if RANDR_12_INTERFACE
925     if (!xf86RandR12Init12 (pScreen))
926         return FALSE;
927 #endif
928     return TRUE;
929 }
930
931 void
932 xf86RandR12CloseScreen (ScreenPtr pScreen)
933 {
934     XF86RandRInfoPtr    randrp;
935
936 #if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(7,0,0,0,0)
937     if (xf86RandR12Key == NULL)
938         return;
939 #endif
940
941     randrp = XF86RANDRINFO(pScreen);
942 #if RANDR_12_INTERFACE
943     xf86Screens[pScreen->myNum]->EnterVT = randrp->orig_EnterVT;
944 #endif
945
946     free(randrp);
947 }
948
949 void
950 xf86RandR12SetRotations (ScreenPtr pScreen, Rotation rotations)
951 {
952     XF86RandRInfoPtr    randrp;
953 #if RANDR_12_INTERFACE
954     ScrnInfoPtr         pScrn = xf86Screens[pScreen->myNum];
955     int                 c;
956     xf86CrtcConfigPtr   config = XF86_CRTC_CONFIG_PTR(pScrn);
957 #endif
958
959 #if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(7,0,0,0,0)
960     if (xf86RandR12Key == NULL)
961         return;
962 #endif
963
964     randrp = XF86RANDRINFO(pScreen);
965 #if RANDR_12_INTERFACE
966     for (c = 0; c < config->num_crtc; c++) {
967         xf86CrtcPtr    crtc = config->crtc[c];
968
969         RRCrtcSetRotations (crtc->randr_crtc, rotations);
970     }
971 #endif
972     randrp->supported_rotations = rotations;
973 }
974
975 void
976 xf86RandR12SetTransformSupport (ScreenPtr pScreen, Bool transforms)
977 {
978     XF86RandRInfoPtr    randrp;
979 #if RANDR_13_INTERFACE
980     ScrnInfoPtr         pScrn = xf86Screens[pScreen->myNum];
981     int                 c;
982     xf86CrtcConfigPtr   config = XF86_CRTC_CONFIG_PTR(pScrn);
983 #endif
984
985 #if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(7,0,0,0,0)
986     if (xf86RandR12Key == NULL)
987         return;
988 #endif
989
990     randrp = XF86RANDRINFO(pScreen);
991 #if RANDR_13_INTERFACE
992     for (c = 0; c < config->num_crtc; c++) {
993         xf86CrtcPtr    crtc = config->crtc[c];
994
995         RRCrtcSetTransformSupport (crtc->randr_crtc, transforms);
996     }
997 #endif
998 }
999
1000 void
1001 xf86RandR12GetOriginalVirtualSize(ScrnInfoPtr pScrn, int *x, int *y)
1002 {
1003     ScreenPtr pScreen = screenInfo.screens[pScrn->scrnIndex];
1004
1005     if (xf86RandR12Generation != serverGeneration ||
1006         XF86RANDRINFO(pScreen)->virtualX == -1)
1007     {
1008         *x = pScrn->virtualX;
1009         *y = pScrn->virtualY;
1010     } else {
1011         XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen);
1012
1013         *x = randrp->virtualX;
1014         *y = randrp->virtualY;
1015     }
1016 }
1017
1018 #if RANDR_12_INTERFACE
1019
1020 #define FLAG_BITS (RR_HSyncPositive | \
1021                    RR_HSyncNegative | \
1022                    RR_VSyncPositive | \
1023                    RR_VSyncNegative | \
1024                    RR_Interlace | \
1025                    RR_DoubleScan | \
1026                    RR_CSync | \
1027                    RR_CSyncPositive | \
1028                    RR_CSyncNegative | \
1029                    RR_HSkewPresent | \
1030                    RR_BCast | \
1031                    RR_PixelMultiplex | \
1032                    RR_DoubleClock | \
1033                    RR_ClockDivideBy2)
1034
1035 static Bool
1036 xf86RandRModeMatches (RRModePtr         randr_mode,
1037                       DisplayModePtr    mode)
1038 {
1039 #if 0
1040     if (match_name)
1041     {
1042         /* check for same name */
1043         int     len = strlen (mode->name);
1044         if (randr_mode->mode.nameLength != len)                 return FALSE;
1045         if (memcmp (randr_mode->name, mode->name, len) != 0)    return FALSE;
1046     }
1047 #endif
1048     
1049     /* check for same timings */
1050     if (randr_mode->mode.dotClock / 1000 != mode->Clock)    return FALSE;
1051     if (randr_mode->mode.width        != mode->HDisplay)    return FALSE;
1052     if (randr_mode->mode.hSyncStart   != mode->HSyncStart)  return FALSE;
1053     if (randr_mode->mode.hSyncEnd     != mode->HSyncEnd)    return FALSE;
1054     if (randr_mode->mode.hTotal       != mode->HTotal)      return FALSE;
1055     if (randr_mode->mode.hSkew        != mode->HSkew)       return FALSE;
1056     if (randr_mode->mode.height       != mode->VDisplay)    return FALSE;
1057     if (randr_mode->mode.vSyncStart   != mode->VSyncStart)  return FALSE;
1058     if (randr_mode->mode.vSyncEnd     != mode->VSyncEnd)    return FALSE;
1059     if (randr_mode->mode.vTotal       != mode->VTotal)      return FALSE;
1060     
1061     /* check for same flags (using only the XF86 valid flag bits) */
1062     if ((randr_mode->mode.modeFlags & FLAG_BITS) != (mode->Flags & FLAG_BITS))
1063         return FALSE;
1064     
1065     /* everything matches */
1066     return TRUE;
1067 }
1068
1069 static Bool
1070 xf86RandR12CrtcNotify (RRCrtcPtr        randr_crtc)
1071 {
1072     ScreenPtr           pScreen = randr_crtc->pScreen;
1073     ScrnInfoPtr         pScrn = xf86Screens[pScreen->myNum];
1074     xf86CrtcConfigPtr   config = XF86_CRTC_CONFIG_PTR(pScrn);
1075     RRModePtr           randr_mode = NULL;
1076     int                 x;
1077     int                 y;
1078     Rotation            rotation;
1079     int                 numOutputs;
1080     RROutputPtr         *randr_outputs;
1081     RROutputPtr         randr_output;
1082     xf86CrtcPtr         crtc = randr_crtc->devPrivate;
1083     xf86OutputPtr       output;
1084     int                 i, j;
1085     DisplayModePtr      mode = &crtc->mode;
1086     Bool                ret;
1087
1088     randr_outputs = malloc(config->num_output * sizeof (RROutputPtr));
1089     if (!randr_outputs)
1090         return FALSE;
1091     x = crtc->x;
1092     y = crtc->y;
1093     rotation = crtc->rotation;
1094     numOutputs = 0;
1095     randr_mode = NULL;
1096     for (i = 0; i < config->num_output; i++)
1097     {
1098         output = config->output[i];
1099         if (output->crtc == crtc)
1100         {
1101             randr_output = output->randr_output;
1102             randr_outputs[numOutputs++] = randr_output;
1103             /*
1104              * We make copies of modes, so pointer equality 
1105              * isn't sufficient
1106              */
1107             for (j = 0; j < randr_output->numModes + randr_output->numUserModes; j++)
1108             {
1109                 RRModePtr   m = (j < randr_output->numModes ?
1110                                  randr_output->modes[j] :
1111                                  randr_output->userModes[j-randr_output->numModes]);
1112                                          
1113                 if (xf86RandRModeMatches (m, mode))
1114                 {
1115                     randr_mode = m;
1116                     break;
1117                 }
1118             }
1119         }
1120     }
1121     ret = RRCrtcNotify (randr_crtc, randr_mode, x, y,
1122                         rotation, 
1123                         crtc->transformPresent ? &crtc->transform : NULL,
1124                         numOutputs, randr_outputs);
1125     free(randr_outputs);
1126     return ret;
1127 }
1128
1129 /*
1130  * Convert a RandR mode to a DisplayMode
1131  */
1132 static void
1133 xf86RandRModeConvert (ScrnInfoPtr       scrn,
1134                       RRModePtr         randr_mode,
1135                       DisplayModePtr    mode)
1136 {
1137     memset(mode, 0, sizeof(DisplayModeRec));
1138     mode->status = MODE_OK;
1139
1140     mode->Clock = randr_mode->mode.dotClock / 1000;
1141     
1142     mode->HDisplay = randr_mode->mode.width;
1143     mode->HSyncStart = randr_mode->mode.hSyncStart;
1144     mode->HSyncEnd = randr_mode->mode.hSyncEnd;
1145     mode->HTotal = randr_mode->mode.hTotal;
1146     mode->HSkew = randr_mode->mode.hSkew;
1147     
1148     mode->VDisplay = randr_mode->mode.height;
1149     mode->VSyncStart = randr_mode->mode.vSyncStart;
1150     mode->VSyncEnd = randr_mode->mode.vSyncEnd;
1151     mode->VTotal = randr_mode->mode.vTotal;
1152     mode->VScan = 0;
1153
1154     mode->Flags = randr_mode->mode.modeFlags & FLAG_BITS;
1155
1156     xf86SetModeCrtc (mode, scrn->adjustFlags);
1157 }
1158
1159 static Bool
1160 xf86RandR12CrtcSet (ScreenPtr       pScreen,
1161                     RRCrtcPtr       randr_crtc,
1162                     RRModePtr       randr_mode,
1163                     int             x,
1164                     int             y,
1165                     Rotation        rotation,
1166                     int             num_randr_outputs,
1167                     RROutputPtr     *randr_outputs)
1168 {
1169     XF86RandRInfoPtr    randrp = XF86RANDRINFO(pScreen);
1170     ScrnInfoPtr         pScrn = xf86Screens[pScreen->myNum];
1171     xf86CrtcConfigPtr   config = XF86_CRTC_CONFIG_PTR(pScrn);
1172     xf86CrtcPtr         crtc = randr_crtc->devPrivate;
1173     RRTransformPtr      transform;
1174     Bool                changed = FALSE;
1175     int                 o, ro;
1176     xf86CrtcPtr         *save_crtcs;
1177     Bool                save_enabled = crtc->enabled;
1178
1179     if (!crtc->scrn->vtSema)
1180         return FALSE;
1181
1182     save_crtcs = malloc(config->num_output * sizeof (xf86CrtcPtr));
1183     if ((randr_mode != NULL) != crtc->enabled)
1184         changed = TRUE;
1185     else if (randr_mode && !xf86RandRModeMatches (randr_mode, &crtc->mode))
1186         changed = TRUE;
1187     
1188     if (rotation != crtc->rotation)
1189         changed = TRUE;
1190
1191     transform = RRCrtcGetTransform (randr_crtc);
1192     if ((transform != NULL) != crtc->transformPresent)
1193         changed = TRUE;
1194     else if (transform && memcmp (&transform->transform, &crtc->transform.transform,
1195                                   sizeof (transform->transform)) != 0)
1196         changed = TRUE;
1197
1198     if (x != crtc->x || y != crtc->y)
1199         changed = TRUE;
1200     for (o = 0; o < config->num_output; o++) 
1201     {
1202         xf86OutputPtr  output = config->output[o];
1203         xf86CrtcPtr    new_crtc;
1204
1205         save_crtcs[o] = output->crtc;
1206         
1207         if (output->crtc == crtc)
1208             new_crtc = NULL;
1209         else
1210             new_crtc = output->crtc;
1211         for (ro = 0; ro < num_randr_outputs; ro++) 
1212             if (output->randr_output == randr_outputs[ro])
1213             {
1214                 new_crtc = crtc;
1215                 break;
1216             }
1217         if (new_crtc != output->crtc)
1218         {
1219             changed = TRUE;
1220             output->crtc = new_crtc;
1221         }
1222     }
1223     for (ro = 0; ro < num_randr_outputs; ro++) 
1224         if (randr_outputs[ro]->pendingProperties)
1225             changed = TRUE;
1226
1227     /* XXX need device-independent mode setting code through an API */
1228     if (changed)
1229     {
1230         crtc->enabled = randr_mode != NULL;
1231
1232         if (randr_mode)
1233         {
1234             DisplayModeRec  mode;
1235             RRTransformPtr  transform = RRCrtcGetTransform (randr_crtc);
1236
1237             xf86RandRModeConvert (pScrn, randr_mode, &mode);
1238             if (!xf86CrtcSetModeTransform (crtc, &mode, rotation, transform, x, y))
1239             {
1240                 crtc->enabled = save_enabled;
1241                 for (o = 0; o < config->num_output; o++)
1242                 {
1243                     xf86OutputPtr       output = config->output[o];
1244                     output->crtc = save_crtcs[o];
1245                 }
1246                 free(save_crtcs);
1247                 return FALSE;
1248             }
1249             xf86RandR13VerifyPanningArea (crtc, pScreen->width, pScreen->height);
1250             xf86RandR13Pan (crtc, randrp->pointerX, randrp->pointerY);
1251             /*
1252              * Save the last successful setting for EnterVT
1253              */
1254             crtc->desiredMode = mode;
1255             crtc->desiredRotation = rotation;
1256             if (transform) {
1257                 crtc->desiredTransform = *transform;
1258                 crtc->desiredTransformPresent = TRUE;
1259             } else
1260                 crtc->desiredTransformPresent = FALSE;
1261
1262             crtc->desiredX = x;
1263             crtc->desiredY = y;
1264         }
1265         xf86DisableUnusedFunctions (pScrn);
1266     }
1267     free(save_crtcs);
1268     return xf86RandR12CrtcNotify (randr_crtc);
1269 }
1270
1271 static Bool
1272 xf86RandR12CrtcSetGamma (ScreenPtr    pScreen,
1273                          RRCrtcPtr    randr_crtc)
1274 {
1275     xf86CrtcPtr         crtc = randr_crtc->devPrivate;
1276
1277     if (crtc->funcs->gamma_set == NULL)
1278         return FALSE;
1279
1280     if (!crtc->scrn->vtSema)
1281         return TRUE;
1282
1283     /* Realloc local gamma if needed. */
1284     if (randr_crtc->gammaSize != crtc->gamma_size) {
1285         CARD16 *tmp_ptr;
1286         tmp_ptr = realloc(crtc->gamma_red, 3 * crtc->gamma_size * sizeof (CARD16));
1287         if (!tmp_ptr)
1288             return FALSE;
1289         crtc->gamma_red = tmp_ptr;
1290         crtc->gamma_green = crtc->gamma_red + crtc->gamma_size;
1291         crtc->gamma_blue = crtc->gamma_green + crtc->gamma_size;
1292     }
1293
1294     crtc->gamma_size = randr_crtc->gammaSize;
1295     memcpy (crtc->gamma_red, randr_crtc->gammaRed, crtc->gamma_size * sizeof (CARD16));
1296     memcpy (crtc->gamma_green, randr_crtc->gammaGreen, crtc->gamma_size * sizeof (CARD16));
1297     memcpy (crtc->gamma_blue, randr_crtc->gammaBlue, crtc->gamma_size * sizeof (CARD16));
1298
1299     /* Only set it when the crtc is actually running.
1300      * Otherwise it will be set when it's activated.
1301      */
1302     if (crtc->active)
1303         crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green,
1304                                                 crtc->gamma_blue, crtc->gamma_size);
1305
1306     return TRUE;
1307 }
1308
1309 static Bool
1310 xf86RandR12CrtcGetGamma (ScreenPtr    pScreen,
1311                          RRCrtcPtr    randr_crtc)
1312 {
1313     xf86CrtcPtr crtc = randr_crtc->devPrivate;
1314
1315     if (!crtc->gamma_size)
1316         return FALSE;
1317
1318     if (!crtc->gamma_red || !crtc->gamma_green || !crtc->gamma_blue)
1319         return FALSE;
1320
1321     /* Realloc randr gamma if needed. */
1322     if (randr_crtc->gammaSize != crtc->gamma_size) {
1323         CARD16 *tmp_ptr;
1324         tmp_ptr = realloc(randr_crtc->gammaRed, 3 * crtc->gamma_size * sizeof (CARD16));
1325         if (!tmp_ptr)
1326             return FALSE;
1327         randr_crtc->gammaRed = tmp_ptr;
1328         randr_crtc->gammaGreen = randr_crtc->gammaRed + crtc->gamma_size;
1329         randr_crtc->gammaBlue = randr_crtc->gammaGreen + crtc->gamma_size;
1330     }
1331     randr_crtc->gammaSize = crtc->gamma_size;
1332     memcpy (randr_crtc->gammaRed, crtc->gamma_red, crtc->gamma_size * sizeof (CARD16));
1333     memcpy (randr_crtc->gammaGreen, crtc->gamma_green, crtc->gamma_size * sizeof (CARD16));
1334     memcpy (randr_crtc->gammaBlue, crtc->gamma_blue, crtc->gamma_size * sizeof (CARD16));
1335
1336     return TRUE;
1337 }
1338
1339 static Bool
1340 xf86RandR12OutputSetProperty (ScreenPtr pScreen,
1341                               RROutputPtr randr_output,
1342                               Atom property,
1343                               RRPropertyValuePtr value)
1344 {
1345     xf86OutputPtr output = randr_output->devPrivate;
1346
1347     /* If we don't have any property handler, then we don't care what the
1348      * user is setting properties to.
1349      */
1350     if (output->funcs->set_property == NULL)
1351         return TRUE;
1352
1353     /*
1354      * This function gets called even when vtSema is FALSE, as
1355      * drivers will need to remember the correct value to apply
1356      * when the VT switch occurs
1357      */
1358     return output->funcs->set_property(output, property, value);
1359 }
1360
1361 static Bool
1362 xf86RandR13OutputGetProperty (ScreenPtr pScreen,
1363                               RROutputPtr randr_output,
1364                               Atom property)
1365 {
1366     xf86OutputPtr output = randr_output->devPrivate;
1367
1368     if (output->funcs->get_property == NULL)
1369         return TRUE;
1370
1371     /* Should be safe even w/o vtSema */
1372     return output->funcs->get_property(output, property);
1373 }
1374
1375 static Bool
1376 xf86RandR12OutputValidateMode (ScreenPtr    pScreen,
1377                                RROutputPtr  randr_output,
1378                                RRModePtr    randr_mode)
1379 {
1380     ScrnInfoPtr     pScrn = xf86Screens[pScreen->myNum];
1381     xf86OutputPtr   output = randr_output->devPrivate;
1382     DisplayModeRec  mode;
1383
1384     xf86RandRModeConvert (pScrn, randr_mode, &mode);
1385     /*
1386      * This function may be called when vtSema is FALSE, so
1387      * the underlying function must either avoid touching the hardware
1388      * or return FALSE when vtSema is FALSE
1389      */
1390     if (output->funcs->mode_valid (output, &mode) != MODE_OK)
1391         return FALSE;
1392     return TRUE;
1393 }
1394
1395 static void
1396 xf86RandR12ModeDestroy (ScreenPtr pScreen, RRModePtr randr_mode)
1397 {
1398 }
1399
1400 /**
1401  * Given a list of xf86 modes and a RandR Output object, construct
1402  * RandR modes and assign them to the output
1403  */
1404 static Bool
1405 xf86RROutputSetModes (RROutputPtr randr_output, DisplayModePtr modes)
1406 {
1407     DisplayModePtr  mode;
1408     RRModePtr       *rrmodes = NULL;
1409     int             nmode = 0;
1410     int             npreferred = 0;
1411     Bool            ret = TRUE;
1412     int             pref;
1413
1414     for (mode = modes; mode; mode = mode->next)
1415         nmode++;
1416
1417     if (nmode) {
1418         rrmodes = malloc(nmode * sizeof (RRModePtr));
1419         
1420         if (!rrmodes)
1421             return FALSE;
1422         nmode = 0;
1423
1424         for (pref = 1; pref >= 0; pref--) {
1425             for (mode = modes; mode; mode = mode->next) {
1426                 if ((pref != 0) == ((mode->type & M_T_PREFERRED) != 0)) {
1427                     xRRModeInfo         modeInfo;
1428                     RRModePtr           rrmode;
1429                     
1430                     modeInfo.nameLength = strlen (mode->name);
1431                     modeInfo.width = mode->HDisplay;
1432                     modeInfo.dotClock = mode->Clock * 1000;
1433                     modeInfo.hSyncStart = mode->HSyncStart;
1434                     modeInfo.hSyncEnd = mode->HSyncEnd;
1435                     modeInfo.hTotal = mode->HTotal;
1436                     modeInfo.hSkew = mode->HSkew;
1437
1438                     modeInfo.height = mode->VDisplay;
1439                     modeInfo.vSyncStart = mode->VSyncStart;
1440                     modeInfo.vSyncEnd = mode->VSyncEnd;
1441                     modeInfo.vTotal = mode->VTotal;
1442                     modeInfo.modeFlags = mode->Flags;
1443
1444                     rrmode = RRModeGet (&modeInfo, mode->name);
1445                     if (rrmode) {
1446                         rrmodes[nmode++] = rrmode;
1447                         npreferred += pref;
1448                     }
1449                 }
1450             }
1451         }
1452     }
1453     
1454     ret = RROutputSetModes (randr_output, rrmodes, nmode, npreferred);
1455     free(rrmodes);
1456     return ret;
1457 }
1458
1459 /*
1460  * Mirror the current mode configuration to RandR
1461  */
1462 static Bool
1463 xf86RandR12SetInfo12 (ScreenPtr pScreen)
1464 {
1465     ScrnInfoPtr         pScrn = xf86Screens[pScreen->myNum];
1466     xf86CrtcConfigPtr   config = XF86_CRTC_CONFIG_PTR(pScrn);
1467     RROutputPtr         *clones;
1468     RRCrtcPtr           *crtcs;
1469     int                 ncrtc;
1470     int                 o, c, l;
1471     RRCrtcPtr           randr_crtc;
1472     int                 nclone;
1473     
1474     clones = malloc(config->num_output * sizeof (RROutputPtr));
1475     crtcs = malloc(config->num_crtc * sizeof (RRCrtcPtr));
1476     for (o = 0; o < config->num_output; o++)
1477     {
1478         xf86OutputPtr   output = config->output[o];
1479         
1480         ncrtc = 0;
1481         for (c = 0; c < config->num_crtc; c++)
1482             if (output->possible_crtcs & (1 << c))
1483                 crtcs[ncrtc++] = config->crtc[c]->randr_crtc;
1484
1485         if (output->crtc)
1486             randr_crtc = output->crtc->randr_crtc;
1487         else
1488             randr_crtc = NULL;
1489
1490         if (!RROutputSetCrtcs (output->randr_output, crtcs, ncrtc))
1491         {
1492             free(crtcs);
1493             free(clones);
1494             return FALSE;
1495         }
1496
1497         RROutputSetPhysicalSize(output->randr_output, 
1498                                 output->mm_width,
1499                                 output->mm_height);
1500         xf86RROutputSetModes (output->randr_output, output->probed_modes);
1501
1502         switch (output->status) {
1503         case XF86OutputStatusConnected:
1504             RROutputSetConnection (output->randr_output, RR_Connected);
1505             break;
1506         case XF86OutputStatusDisconnected:
1507             RROutputSetConnection (output->randr_output, RR_Disconnected);
1508             break;
1509         case XF86OutputStatusUnknown:
1510             RROutputSetConnection (output->randr_output, RR_UnknownConnection);
1511             break;
1512         }
1513
1514         RROutputSetSubpixelOrder (output->randr_output, output->subpixel_order);
1515
1516         /*
1517          * Valid clones
1518          */
1519         nclone = 0;
1520         for (l = 0; l < config->num_output; l++)
1521         {
1522             xf86OutputPtr           clone = config->output[l];
1523             
1524             if (l != o && (output->possible_clones & (1 << l)))
1525                 clones[nclone++] = clone->randr_output;
1526         }
1527         if (!RROutputSetClones (output->randr_output, clones, nclone))
1528         {
1529             free(crtcs);
1530             free(clones);
1531             return FALSE;
1532         }
1533     }
1534     free(crtcs);
1535     free(clones);
1536     return TRUE;
1537 }
1538
1539
1540
1541 /*
1542  * Query the hardware for the current state, then mirror
1543  * that to RandR
1544  */
1545 static Bool
1546 xf86RandR12GetInfo12 (ScreenPtr pScreen, Rotation *rotations)
1547 {
1548     ScrnInfoPtr         pScrn = xf86Screens[pScreen->myNum];
1549
1550     if (!pScrn->vtSema)
1551         return TRUE;
1552     xf86ProbeOutputModes (pScrn, 0, 0);
1553     xf86SetScrnInfoModes (pScrn);
1554     return xf86RandR12SetInfo12 (pScreen);
1555 }
1556
1557 static Bool
1558 xf86RandR12CreateObjects12 (ScreenPtr pScreen)
1559 {
1560     ScrnInfoPtr         pScrn = xf86Screens[pScreen->myNum];
1561     xf86CrtcConfigPtr   config = XF86_CRTC_CONFIG_PTR(pScrn);
1562     int                 c;
1563     int                 o;
1564     
1565     if (!RRInit ())
1566         return FALSE;
1567
1568     /*
1569      * Configure crtcs
1570      */
1571     for (c = 0; c < config->num_crtc; c++)
1572     {
1573         xf86CrtcPtr    crtc = config->crtc[c];
1574         
1575         crtc->randr_crtc = RRCrtcCreate (pScreen, crtc);
1576         RRCrtcGammaSetSize (crtc->randr_crtc, 256);
1577     }
1578     /*
1579      * Configure outputs
1580      */
1581     for (o = 0; o < config->num_output; o++)
1582     {
1583         xf86OutputPtr   output = config->output[o];
1584
1585         output->randr_output = RROutputCreate (pScreen, output->name, 
1586                                                strlen (output->name),
1587                                                output);
1588
1589         if (output->funcs->create_resources != NULL)
1590             output->funcs->create_resources(output);
1591         RRPostPendingProperties (output->randr_output);
1592     }
1593     return TRUE;
1594 }
1595
1596 static Bool
1597 xf86RandR12CreateScreenResources12 (ScreenPtr pScreen)
1598 {
1599     int                 c;
1600     ScrnInfoPtr         pScrn = xf86Screens[pScreen->myNum];
1601     xf86CrtcConfigPtr   config = XF86_CRTC_CONFIG_PTR(pScrn);
1602
1603 #if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(7,0,0,0,0)
1604     if (xf86RandR12Key == NULL)
1605         return TRUE;
1606 #endif
1607
1608     for (c = 0; c < config->num_crtc; c++)
1609         xf86RandR12CrtcNotify (config->crtc[c]->randr_crtc);
1610     
1611     RRScreenSetSizeRange (pScreen, config->minWidth, config->minHeight,
1612                           config->maxWidth, config->maxHeight);
1613     return TRUE;
1614 }
1615
1616 /*
1617  * Something happened within the screen configuration due
1618  * to DGA, VidMode or hot key. Tell RandR
1619  */
1620
1621 void
1622 xf86RandR12TellChanged (ScreenPtr pScreen)
1623 {
1624     ScrnInfoPtr         pScrn = xf86Screens[pScreen->myNum];
1625     xf86CrtcConfigPtr   config = XF86_CRTC_CONFIG_PTR(pScrn);
1626     int                 c;
1627
1628 #if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(7,0,0,0,0)
1629     if (xf86RandR12Key == NULL)
1630         return;
1631 #else
1632     if (!XF86RANDRINFO(pScreen))
1633         return;
1634 #endif
1635
1636     xf86RandR12SetInfo12 (pScreen);
1637     for (c = 0; c < config->num_crtc; c++)
1638         xf86RandR12CrtcNotify (config->crtc[c]->randr_crtc);
1639
1640     RRTellChanged (pScreen);
1641 }
1642
1643 static void
1644 xf86RandR12PointerMoved (int scrnIndex, int x, int y)
1645 {
1646     ScreenPtr           pScreen = screenInfo.screens[scrnIndex];
1647     ScrnInfoPtr         pScrn   = XF86SCRNINFO(pScreen);
1648     xf86CrtcConfigPtr   config  = XF86_CRTC_CONFIG_PTR(pScrn);
1649     XF86RandRInfoPtr    randrp  = XF86RANDRINFO(pScreen);
1650     int c;
1651
1652     randrp->pointerX = x;
1653     randrp->pointerY = y;
1654     for (c = 0; c < config->num_crtc; c++)
1655         xf86RandR13Pan (config->crtc[c], x, y);
1656 }
1657
1658 static Bool
1659 xf86RandR13GetPanning (ScreenPtr           pScreen,
1660                        RRCrtcPtr           randr_crtc,
1661                        BoxPtr              totalArea,
1662                        BoxPtr              trackingArea,
1663                        INT16               *border)
1664 {
1665     xf86CrtcPtr         crtc = randr_crtc->devPrivate;
1666
1667     if (crtc->version < 2)
1668         return FALSE;
1669     if (totalArea)
1670         memcpy (totalArea,    &crtc->panningTotalArea,    sizeof(BoxRec));
1671     if (trackingArea)
1672         memcpy (trackingArea, &crtc->panningTrackingArea, sizeof(BoxRec));
1673     if (border)
1674         memcpy (border,        crtc->panningBorder,       4*sizeof(INT16));
1675
1676     return TRUE;
1677 }
1678
1679 static Bool
1680 xf86RandR13SetPanning (ScreenPtr           pScreen,
1681                        RRCrtcPtr           randr_crtc,
1682                        BoxPtr              totalArea,
1683                        BoxPtr              trackingArea,
1684                        INT16               *border)
1685 {
1686     XF86RandRInfoPtr    randrp  = XF86RANDRINFO(pScreen);
1687     xf86CrtcPtr         crtc = randr_crtc->devPrivate;
1688     BoxRec              oldTotalArea;
1689     BoxRec              oldTrackingArea;
1690     INT16               oldBorder[4];
1691
1692
1693     if (crtc->version < 2)
1694         return FALSE;
1695
1696     memcpy (&oldTotalArea,    &crtc->panningTotalArea,    sizeof(BoxRec));
1697     memcpy (&oldTrackingArea, &crtc->panningTrackingArea, sizeof(BoxRec));
1698     memcpy (oldBorder,         crtc->panningBorder,       4*sizeof(INT16));
1699
1700     if (totalArea)
1701         memcpy (&crtc->panningTotalArea, totalArea, sizeof(BoxRec));
1702     if (trackingArea)
1703         memcpy (&crtc->panningTrackingArea, trackingArea, sizeof(BoxRec));
1704     if (border)
1705         memcpy (crtc->panningBorder, border, 4*sizeof(INT16));
1706
1707     if (xf86RandR13VerifyPanningArea (crtc, pScreen->width, pScreen->height)) {
1708         xf86RandR13Pan (crtc, randrp->pointerX, randrp->pointerY);
1709         return TRUE;
1710     } else {
1711         /* Restore old settings */
1712         memcpy (&crtc->panningTotalArea,    &oldTotalArea,    sizeof(BoxRec));
1713         memcpy (&crtc->panningTrackingArea, &oldTrackingArea, sizeof(BoxRec));
1714         memcpy (crtc->panningBorder,         oldBorder,       4*sizeof(INT16));
1715         return FALSE;
1716     }
1717 }
1718
1719 /*
1720  * Compatibility with XF86VidMode's gamma changer.  This necessarily clobbers
1721  * any per-crtc setup.  You asked for it...
1722  */
1723
1724 static void
1725 gamma_to_ramp(float gamma, CARD16 *ramp, int size)
1726 {
1727     int i;
1728
1729     for (i = 0; i < size; i++) {
1730         if (gamma == 1.0)
1731             ramp[i] = i << 8;
1732         else
1733             ramp[i] = (CARD16)(pow((double)i / (double)(size - 1), 1. / gamma)
1734                                * (double)(size - 1) * 256);
1735     }
1736 }
1737
1738 static int
1739 xf86RandR12ChangeGamma(int scrnIndex, Gamma gamma)
1740 {
1741     CARD16 *points, *red, *green, *blue;
1742     ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
1743     RRCrtcPtr crtc = xf86CompatRRCrtc(pScrn);
1744     int size;
1745
1746     if (!crtc)
1747         return Success;
1748
1749     size = max(0, crtc->gammaSize);
1750     if (!size)
1751         return Success;
1752
1753     points = calloc(size, 3 * sizeof(CARD16));
1754     if (!points)
1755         return BadAlloc;
1756
1757     red = points;
1758     green = points + size;
1759     blue = points + 2 * size;
1760
1761     gamma_to_ramp(gamma.red, red, size);
1762     gamma_to_ramp(gamma.green, green, size);
1763     gamma_to_ramp(gamma.blue, blue, size);
1764     RRCrtcGammaSet(crtc, red, green, blue);
1765
1766     free(points);
1767
1768     pScrn->gamma = gamma;
1769
1770     return Success;
1771 }
1772
1773 static Bool
1774 xf86RandR12EnterVT (int screen_index, int flags)
1775 {
1776     ScreenPtr        pScreen = screenInfo.screens[screen_index];
1777     ScrnInfoPtr      pScrn = xf86Screens[screen_index];
1778     XF86RandRInfoPtr randrp  = XF86RANDRINFO(pScreen);
1779     rrScrPrivPtr     rp = rrGetScrPriv(pScreen);
1780     Bool             ret;
1781
1782     if (randrp->orig_EnterVT) {
1783         pScrn->EnterVT = randrp->orig_EnterVT;
1784         ret = pScrn->EnterVT (screen_index, flags);
1785         randrp->orig_EnterVT = pScrn->EnterVT;
1786         pScrn->EnterVT = xf86RandR12EnterVT;
1787         if (!ret)
1788             return FALSE;
1789     }
1790
1791     /* reload gamma */
1792     int i;
1793     for (i = 0; i < rp->numCrtcs; i++)
1794         xf86RandR12CrtcSetGamma(pScreen, rp->crtcs[i]);
1795
1796     return RRGetInfo (pScreen, TRUE); /* force a re-probe of outputs and notify clients about changes */
1797 }
1798
1799 static Bool
1800 xf86RandR12Init12 (ScreenPtr pScreen)
1801 {
1802     ScrnInfoPtr         pScrn = xf86Screens[pScreen->myNum];
1803     rrScrPrivPtr        rp = rrGetScrPriv(pScreen);
1804     XF86RandRInfoPtr    randrp  = XF86RANDRINFO(pScreen);
1805     int i;
1806
1807     rp->rrGetInfo = xf86RandR12GetInfo12;
1808     rp->rrScreenSetSize = xf86RandR12ScreenSetSize;
1809     rp->rrCrtcSet = xf86RandR12CrtcSet;
1810     rp->rrCrtcSetGamma = xf86RandR12CrtcSetGamma;
1811     rp->rrCrtcGetGamma = xf86RandR12CrtcGetGamma;
1812     rp->rrOutputSetProperty = xf86RandR12OutputSetProperty;
1813     rp->rrOutputValidateMode = xf86RandR12OutputValidateMode;
1814 #if RANDR_13_INTERFACE
1815     rp->rrOutputGetProperty = xf86RandR13OutputGetProperty;
1816     rp->rrGetPanning = xf86RandR13GetPanning;
1817     rp->rrSetPanning = xf86RandR13SetPanning;
1818 #endif
1819     rp->rrModeDestroy = xf86RandR12ModeDestroy;
1820     rp->rrSetConfig = NULL;
1821     pScrn->PointerMoved = xf86RandR12PointerMoved;
1822     pScrn->ChangeGamma = xf86RandR12ChangeGamma;
1823
1824     randrp->orig_EnterVT = pScrn->EnterVT;
1825     pScrn->EnterVT = xf86RandR12EnterVT;
1826
1827     if (!xf86RandR12CreateObjects12 (pScreen))
1828         return FALSE;
1829
1830     /*
1831      * Configure output modes
1832      */
1833     if (!xf86RandR12SetInfo12 (pScreen))
1834         return FALSE;
1835     for (i = 0; i < rp->numCrtcs; i++) {
1836         xf86RandR12CrtcGetGamma(pScreen, rp->crtcs[i]);
1837     }
1838     return TRUE;
1839 }
1840
1841 #endif
1842
1843 Bool
1844 xf86RandR12PreInit (ScrnInfoPtr pScrn)
1845 {
1846     return TRUE;
1847 }