Logo Search packages:      
Sourcecode: xserver-xorg-video-ati version File versions

xf86RandR12.c

/*
 * Copyright  2002 Keith Packard, member of The XFree86 Project, Inc.
 *
 * Permission to use, copy, modify, distribute, and sell this software and its
 * documentation for any purpose is hereby granted without fee, provided that
 * the above copyright notice appear in all copies and that both that copyright
 * notice and this permission notice appear in supporting documentation, and
 * that the name of the copyright holders not be used in advertising or
 * publicity pertaining to distribution of the software without specific,
 * written prior permission.  The copyright holders make no representations
 * about the suitability of this software for any purpose.  It is provided "as
 * is" without express or implied warranty.
 *
 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
 * OF THIS SOFTWARE.
 */

#ifdef HAVE_XORG_CONFIG_H
#include <xorg-config.h>
#else
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#endif

#include "xf86.h"
#include "os.h"
#include "mibank.h"
#include "globals.h"
#include "xf86.h"
#include "xf86Priv.h"
#include "xf86DDC.h"
#include "mipointer.h"
#include "windowstr.h"
#include "inputstr.h"
#include <randrstr.h>
#include <X11/extensions/render.h>

#include "xf86Crtc.h"
#include "xf86RandR12.h"

typedef struct _xf86RandR12Info {
    int                           virtualX;
    int                           virtualY;
    int                           mmWidth;
    int                           mmHeight;
    int                           maxX;
    int                           maxY;
    int                           pointerX;
    int                           pointerY;
    Rotation                      rotation; /* current mode */
    Rotation                        supported_rotations; /* driver supported */
} XF86RandRInfoRec, *XF86RandRInfoPtr;

#ifdef RANDR_12_INTERFACE
static Bool xf86RandR12Init12 (ScreenPtr pScreen);
static Bool xf86RandR12CreateScreenResources12 (ScreenPtr pScreen);
#endif

static int xf86RandR12Generation;
#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(7,0,0,0,0)

static int xf86RandR12KeyIndex;
static DevPrivateKey xf86RandR12Key;
#define XF86RANDRINFO(p) ((XF86RandRInfoPtr) \
    dixLookupPrivate(&(p)->devPrivates, xf86RandR12Key))

#else /* XORG_VERSION_CURRENT < 7.0 */

static int xf86RandR12Index;
#define XF86RANDRINFO(p) \
    ((XF86RandRInfoPtr)(p)->devPrivates[xf86RandR12Index].ptr)

#endif /* XORG_VERSION_CURRENT < 7.0 */


static int
xf86RandR12ModeRefresh (DisplayModePtr mode)
{
    if (mode->VRefresh)
      return (int) (mode->VRefresh + 0.5);
    else
      return (int) (mode->Clock * 1000.0 / mode->HTotal / mode->VTotal + 0.5);
}

/* Adapt panning area; return TRUE if panning area was valid without adaption */
static int
xf86RandR13VerifyPanningArea (xf86CrtcPtr crtc, int screenWidth, int screenHeight)
{
    int ret = TRUE;

    if (crtc->version < 2)
      return FALSE;

    if (crtc->panningTotalArea.x2 <= crtc->panningTotalArea.x1) {
      /* Panning in X is disabled */
      if (crtc->panningTotalArea.x1 || crtc->panningTotalArea.x2)
          /* Illegal configuration -> fail/disable */
          ret = FALSE;
      crtc->panningTotalArea.x1    = crtc->panningTotalArea.x2    = 0;
      crtc->panningTrackingArea.x1 = crtc->panningTrackingArea.x2 = 0;
      crtc->panningBorder[0]       = crtc->panningBorder[2]       = 0;
    } else {
      /* Panning in X is enabled */
      if (crtc->panningTotalArea.x1 < 0) {
          /* Panning region outside screen -> move inside */
          crtc->panningTotalArea.x2 -= crtc->panningTotalArea.x1;
          crtc->panningTotalArea.x1 = 0;
          ret = FALSE;
      }
      if (crtc->panningTotalArea.x2 < crtc->panningTotalArea.x1 + crtc->mode.HDisplay) {
          /* Panning region smaller than displayed area -> crop to displayed area */
          crtc->panningTotalArea.x2 = crtc->panningTotalArea.x1 + crtc->mode.HDisplay;
          ret = FALSE;
      }
      if (crtc->panningTotalArea.x2 > screenWidth) {
          /* Panning region larger than screen -> move inside, then crop to screen */
          crtc->panningTotalArea.x1 -= crtc->panningTotalArea.x2 - screenWidth;
          crtc->panningTotalArea.x2 = screenWidth;
          ret = FALSE;
          if (crtc->panningTotalArea.x1 < 0)
            crtc->panningTotalArea.x1 = 0;
      }
      if (crtc->panningBorder[0] + crtc->panningBorder[2] > crtc->mode.HDisplay) {
          /* Borders too large -> set to 0 */
          crtc->panningBorder[0] = crtc->panningBorder[2] = 0;
          ret = FALSE;
      }
    }

    if (crtc->panningTotalArea.y2 <= crtc->panningTotalArea.y1) {
      /* Panning in Y is disabled */
      if (crtc->panningTotalArea.y1 || crtc->panningTotalArea.y2)
          /* Illegal configuration -> fail/disable */
          ret = FALSE;
      crtc->panningTotalArea.y1    = crtc->panningTotalArea.y2    = 0;
      crtc->panningTrackingArea.y1 = crtc->panningTrackingArea.y2 = 0;
      crtc->panningBorder[1]       = crtc->panningBorder[3]       = 0;
    } else {
      /* Panning in Y is enabled */
      if (crtc->panningTotalArea.y1 < 0) {
          /* Panning region outside screen -> move inside */
          crtc->panningTotalArea.y2 -= crtc->panningTotalArea.y1;
          crtc->panningTotalArea.y1 = 0;
          ret = FALSE;
      }
      if (crtc->panningTotalArea.y2 < crtc->panningTotalArea.y1 + crtc->mode.VDisplay) {
          /* Panning region smaller than displayed area -> crop to displayed area */
          crtc->panningTotalArea.y2 = crtc->panningTotalArea.y1 + crtc->mode.VDisplay;
          ret = FALSE;
      }
      if (crtc->panningTotalArea.y2 > screenHeight) {
          /* Panning region larger than screen -> move inside, then crop to screen */
          crtc->panningTotalArea.y1 -= crtc->panningTotalArea.y2 - screenHeight;
          crtc->panningTotalArea.y2 = screenHeight;
          ret = FALSE;
          if (crtc->panningTotalArea.y1 < 0)
            crtc->panningTotalArea.y1 = 0;
      }
      if (crtc->panningBorder[1] + crtc->panningBorder[3] > crtc->mode.VDisplay) {
          /* Borders too large -> set to 0 */
          crtc->panningBorder[1] = crtc->panningBorder[3] = 0;
          ret = FALSE;
      }
    }

    return ret;
}

static void
xf86RandR13Pan (xf86CrtcPtr crtc, int x, int y)
{
    int newX, newY;
    int width, height;

    if (crtc->version < 2)
      return;

    if (! crtc->enabled                               ||
      (crtc->panningTotalArea.x2 <= crtc->panningTotalArea.x1     &&
       crtc->panningTotalArea.y2 <= crtc->panningTotalArea.y1))
      return;

    newX   = crtc->x;
    newY   = crtc->y;
    width  = crtc->mode.HDisplay;
    height = crtc->mode.VDisplay;

    if ((crtc->panningTrackingArea.x2 <= crtc->panningTrackingArea.x1 ||
       (x >= crtc->panningTrackingArea.x1 && x < crtc->panningTrackingArea.x2)) &&
      (crtc->panningTrackingArea.y2 <= crtc->panningTrackingArea.y1 ||
       (y >= crtc->panningTrackingArea.y1 && y < crtc->panningTrackingArea.y2))) {
      if (crtc->panningTotalArea.x2 > crtc->panningTotalArea.x1) {
          if (x < crtc->x + crtc->panningBorder[0])
            newX = x - crtc->panningBorder[0];
          if (x >= crtc->x + width - crtc->panningBorder[2])
            newX = x - width + crtc->panningBorder[2] + 1;
      }
      if (crtc->panningTotalArea.y2 > crtc->panningTotalArea.y1) {
          if (y < crtc->y + crtc->panningBorder[1])
            newY = y - crtc->panningBorder[1];
          if (y >= crtc->y + height - crtc->panningBorder[3])
            newY = y - height + crtc->panningBorder[3] + 1;
      }
    }
    /* Validate against [xy]1 after [xy]2, to be sure that results are > 0 for [xy]1 > 0 */
    if (crtc->panningTotalArea.x2 > crtc->panningTotalArea.x1) {
      if (newX > crtc->panningTotalArea.x2 - width)
          newX =  crtc->panningTotalArea.x2 - width;
      if (newX <  crtc->panningTotalArea.x1)
          newX =  crtc->panningTotalArea.x1;
    }
    if (crtc->panningTotalArea.y2 > crtc->panningTotalArea.y1) {
      if (newY > crtc->panningTotalArea.y2 - height)
          newY =  crtc->panningTotalArea.y2 - height;
      if (newY <  crtc->panningTotalArea.y1)
          newY =  crtc->panningTotalArea.y1;
    }
    if (newX != crtc->x || newY != crtc->y)
      xf86CrtcSetOrigin (crtc, newX, newY);
}

static Bool
xf86RandR12GetInfo (ScreenPtr pScreen, Rotation *rotations)
{
    RRScreenSizePtr         pSize;
    ScrnInfoPtr             scrp = XF86SCRNINFO(pScreen);
    XF86RandRInfoPtr        randrp = XF86RANDRINFO(pScreen);
    DisplayModePtr          mode;
    int                     refresh0 = 60;
    int                     maxX = 0, maxY = 0;

    *rotations = randrp->supported_rotations;

    if (randrp->virtualX == -1 || randrp->virtualY == -1)
    {
      randrp->virtualX = scrp->virtualX;
      randrp->virtualY = scrp->virtualY;
    }

    /* Re-probe the outputs for new monitors or modes */
    if (scrp->vtSema)
    {
      xf86ProbeOutputModes (scrp, 0, 0);
      xf86SetScrnInfoModes (scrp);
#ifdef XFreeXDGA
      xf86DiDGAReInit (pScreen);
#endif
    }

    for (mode = scrp->modes; ; mode = mode->next)
    {
      int refresh = xf86RandR12ModeRefresh (mode);
      if (randrp->maxX == 0 || randrp->maxY == 0)
      {
            if (maxX < mode->HDisplay)
                  maxX = mode->HDisplay;
            if (maxY < mode->VDisplay)
                  maxY = mode->VDisplay;
      }
      if (mode == scrp->modes)
          refresh0 = refresh;
      pSize = RRRegisterSize (pScreen,
                        mode->HDisplay, mode->VDisplay,
                        randrp->mmWidth, randrp->mmHeight);
      if (!pSize)
          return FALSE;
      RRRegisterRate (pScreen, pSize, refresh);

      if (xf86ModesEqual(mode, scrp->currentMode))
      {
          RRSetCurrentConfig (pScreen, randrp->rotation, refresh, pSize);
      }
      if (mode->next == scrp->modes)
          break;
    }

    if (randrp->maxX == 0 || randrp->maxY == 0)
    {
      randrp->maxX = maxX;
      randrp->maxY = maxY;
    }

    return TRUE;
}

static Bool
xf86RandR12SetMode (ScreenPtr     pScreen,
              DisplayModePtr    mode,
              Bool                useVirtual,
              int           mmWidth,
              int           mmHeight)
{
    ScrnInfoPtr         scrp = XF86SCRNINFO(pScreen);
    XF86RandRInfoPtr    randrp = XF86RANDRINFO(pScreen);
    int                 oldWidth = pScreen->width;
    int                 oldHeight = pScreen->height;
    int                 oldmmWidth = pScreen->mmWidth;
    int                 oldmmHeight = pScreen->mmHeight;
    WindowPtr           pRoot = WindowTable[pScreen->myNum];
    DisplayModePtr      currentMode = NULL;
    Bool          ret = TRUE;
    PixmapPtr           pspix = NULL;

    if (pRoot)
      (*scrp->EnableDisableFBAccess) (pScreen->myNum, FALSE);
    if (useVirtual)
    {
      scrp->virtualX = randrp->virtualX;
      scrp->virtualY = randrp->virtualY;
    }
    else
    {
      scrp->virtualX = mode->HDisplay;
      scrp->virtualY = mode->VDisplay;
    }

    if(randrp->rotation & (RR_Rotate_90 | RR_Rotate_270))
    {
      /* If the screen is rotated 90 or 270 degrees, swap the sizes. */
      pScreen->width = scrp->virtualY;
      pScreen->height = scrp->virtualX;
      pScreen->mmWidth = mmHeight;
      pScreen->mmHeight = mmWidth;
    }
    else
    {
      pScreen->width = scrp->virtualX;
      pScreen->height = scrp->virtualY;
      pScreen->mmWidth = mmWidth;
      pScreen->mmHeight = mmHeight;
    }
    if (scrp->currentMode == mode) {
        /* Save current mode */
        currentMode = scrp->currentMode;
        /* Reset, just so we ensure the drivers SwitchMode is called */
        scrp->currentMode = NULL;
    }
    /*
     * We know that if the driver failed to SwitchMode to the rotated
     * version, then it should revert back to it's prior mode.
     */
    if (!xf86SwitchMode (pScreen, mode))
    {
        ret = FALSE;
      scrp->virtualX = pScreen->width = oldWidth;
      scrp->virtualY = pScreen->height = oldHeight;
      pScreen->mmWidth = oldmmWidth;
      pScreen->mmHeight = oldmmHeight;
        scrp->currentMode = currentMode;
    }
    /*
     * Get the new Screen pixmap ptr as SwitchMode might have called
     * ModifyPixmapHeader and xf86EnableDisableFBAccess will put it back...
     * Unfortunately.
     */
    pspix = (*pScreen->GetScreenPixmap) (pScreen);
    if (pspix->devPrivate.ptr)
       scrp->pixmapPrivate = pspix->devPrivate;

    /*
     * Make sure the layout is correct
     */
    xf86ReconfigureLayout();

    /*
     * Make sure the whole screen is visible
     */
    xf86SetViewport (pScreen, pScreen->width, pScreen->height);
    xf86SetViewport (pScreen, 0, 0);
    if (pRoot)
      (*scrp->EnableDisableFBAccess) (pScreen->myNum, TRUE);
    return ret;
}

Bool
xf86RandR12SetConfig (ScreenPtr           pScreen,
                Rotation            rotation,
                int                 rate,
                RRScreenSizePtr     pSize)
{
    ScrnInfoPtr         scrp = XF86SCRNINFO(pScreen);
    XF86RandRInfoPtr    randrp = XF86RANDRINFO(pScreen);
    DisplayModePtr      mode;
    int                 px, py;
    Bool          useVirtual = FALSE;
    int                 maxX = 0, maxY = 0;
    Rotation            oldRotation = randrp->rotation;

    randrp->rotation = rotation;

    if (randrp->virtualX == -1 || randrp->virtualY == -1)
    {
      randrp->virtualX = scrp->virtualX;
      randrp->virtualY = scrp->virtualY;
    }

    miPointerGetPosition (inputInfo.pointer, &px, &py);
    for (mode = scrp->modes; ; mode = mode->next)
    {
      if (randrp->maxX == 0 || randrp->maxY == 0)
      {
            if (maxX < mode->HDisplay)
                  maxX = mode->HDisplay;
            if (maxY < mode->VDisplay)
                  maxY = mode->VDisplay;
      }
      if (mode->HDisplay == pSize->width &&
          mode->VDisplay == pSize->height &&
          (rate == 0 || xf86RandR12ModeRefresh (mode) == rate))
          break;
      if (mode->next == scrp->modes)
      {
          if (pSize->width == randrp->virtualX &&
            pSize->height == randrp->virtualY)
          {
            mode = scrp->modes;
            useVirtual = TRUE;
            break;
          }
          if (randrp->maxX == 0 || randrp->maxY == 0)
          {
            randrp->maxX = maxX;
            randrp->maxY = maxY;
          }
          return FALSE;
      }
    }

    if (randrp->maxX == 0 || randrp->maxY == 0)
    {
      randrp->maxX = maxX;
      randrp->maxY = maxY;
    }

    if (!xf86RandR12SetMode (pScreen, mode, useVirtual, pSize->mmWidth,
                     pSize->mmHeight)) {
        randrp->rotation = oldRotation;
      return FALSE;
    }

    /*
     * Move the cursor back where it belongs; SwitchMode repositions it
     */
    if (pScreen == miPointerGetScreen(inputInfo.pointer))
    {
        px = (px >= pScreen->width ? (pScreen->width - 1) : px);
        py = (py >= pScreen->height ? (pScreen->height - 1) : py);

      xf86SetViewport(pScreen, px, py);

      (*pScreen->SetCursorPosition) (inputInfo.pointer, pScreen, px, py, FALSE);
    }

    return TRUE;
}

static Bool
xf86RandR12ScreenSetSize (ScreenPtr pScreen,
                  CARD16            width,
                  CARD16            height,
                  CARD32            mmWidth,
                  CARD32            mmHeight)
{
    XF86RandRInfoPtr    randrp = XF86RANDRINFO(pScreen);
    ScrnInfoPtr         pScrn = XF86SCRNINFO(pScreen);
    xf86CrtcConfigPtr   config = XF86_CRTC_CONFIG_PTR(pScrn);
    WindowPtr           pRoot = WindowTable[pScreen->myNum];
    PixmapPtr           pScrnPix = (*pScreen->GetScreenPixmap)(pScreen);
    Bool          ret = FALSE;
    int                 c;

#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(7,0,0,0,0)
    if (xf86RandR12Key) {
#endif
        if (randrp->virtualX == -1 || randrp->virtualY == -1)
        {
          randrp->virtualX = pScrn->virtualX;
          randrp->virtualY = pScrn->virtualY;
        }
#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(7,0,0,0,0)
    }
#endif
    if (pRoot && pScrn->vtSema)
      (*pScrn->EnableDisableFBAccess) (pScreen->myNum, FALSE);

    /* Let the driver update virtualX and virtualY */
    if (!(*config->funcs->resize)(pScrn, width, height))
      goto finish;

    ret = TRUE;
    /* Update panning information */
    for (c = 0; c < config->num_crtc; c++) {
      xf86CrtcPtr crtc = config->crtc[c];
      if (crtc->panningTotalArea.x2 > crtc->panningTotalArea.x1 ||
          crtc->panningTotalArea.y2 > crtc->panningTotalArea.y1) {
          if (crtc->panningTotalArea.x2 > crtc->panningTrackingArea.x1)
            crtc->panningTotalArea.x2 += width  - pScreen->width;
          if (crtc->panningTotalArea.y2 > crtc->panningTrackingArea.y1)
            crtc->panningTotalArea.y2 += height - pScreen->height;
          if (crtc->panningTrackingArea.x2 > crtc->panningTrackingArea.x1)
            crtc->panningTrackingArea.x2 += width  - pScreen->width;
          if (crtc->panningTrackingArea.y2 > crtc->panningTrackingArea.y1)
            crtc->panningTrackingArea.y2 += height - pScreen->height;
          xf86RandR13VerifyPanningArea (crtc, width, height);
          xf86RandR13Pan (crtc, randrp->pointerX, randrp->pointerY);
      }
    }

    pScreen->width = pScrnPix->drawable.width = width;
    pScreen->height = pScrnPix->drawable.height = height;
    randrp->mmWidth = pScreen->mmWidth = mmWidth;
    randrp->mmHeight = pScreen->mmHeight = mmHeight;

    xf86SetViewport (pScreen, pScreen->width-1, pScreen->height-1);
    xf86SetViewport (pScreen, 0, 0);

finish:
    if (pRoot && pScrn->vtSema)
      (*pScrn->EnableDisableFBAccess) (pScreen->myNum, TRUE);
#if RANDR_12_INTERFACE
    if (xf86RandR12Key && WindowTable[pScreen->myNum] && ret)
      RRScreenSizeNotify (pScreen);
#endif
    return ret;
}

Rotation
xf86RandR12GetRotation(ScreenPtr pScreen)
{
    XF86RandRInfoPtr        randrp = XF86RANDRINFO(pScreen);

    return randrp->rotation;
}

Bool
xf86RandR12CreateScreenResources (ScreenPtr pScreen)
{
    ScrnInfoPtr         pScrn = xf86Screens[pScreen->myNum];
    xf86CrtcConfigPtr   config = XF86_CRTC_CONFIG_PTR(pScrn);
    XF86RandRInfoPtr    randrp = XF86RANDRINFO(pScreen);
    int                 c;
    int                 width, height;
    int                 mmWidth, mmHeight;
#ifdef PANORAMIX
    /* XXX disable RandR when using Xinerama */
    if (!noPanoramiXExtension)
      return TRUE;
#endif

    /*
     * Compute size of screen
     */
    width = 0; height = 0;
    for (c = 0; c < config->num_crtc; c++)
    {
      xf86CrtcPtr crtc = config->crtc[c];
      int       crtc_width = crtc->x + xf86ModeWidth (&crtc->mode, crtc->rotation);
      int       crtc_height = crtc->y + xf86ModeHeight (&crtc->mode, crtc->rotation);
      
      if (crtc->enabled) {
          if (crtc_width > width)
            width = crtc_width;
          if (crtc_height > height)
            height = crtc_height;
          if (crtc->panningTotalArea.x2 > width)
            width = crtc->panningTotalArea.x2;
          if (crtc->panningTotalArea.y2 > height)
            height = crtc->panningTotalArea.y2;
      }
    }
    
    if (width && height)
    {
      /*
       * Compute physical size of screen
       */
      if (monitorResolution) 
      {
          mmWidth = width * 25.4 / monitorResolution;
          mmHeight = height * 25.4 / monitorResolution;
      }
      else
      {
          xf86OutputPtr   output = config->output[config->compat_output];
          xf86CrtcPtr       crtc = output->crtc;

          if (output->conf_monitor &&
            (output->conf_monitor->mon_width  > 0 &&
             output->conf_monitor->mon_height > 0))
          {
            /*
             * Prefer user configured DisplaySize
             */
            mmWidth = output->conf_monitor->mon_width;
            mmHeight = output->conf_monitor->mon_height;
          }
          else if (crtc && crtc->mode.HDisplay &&
                 output->mm_width && output->mm_height)
          {
            /*
             * If the output has a mode and a declared size, use that
             * to scale the screen size
             */
            DisplayModePtr    mode = &crtc->mode;
            mmWidth = output->mm_width * width / mode->HDisplay;
            mmHeight = output->mm_height * height / mode->VDisplay;
          }
          else
          {
            /*
             * Otherwise, just set the screen to DEFAULT_DPI
             */
            mmWidth = width * 25.4 / DEFAULT_DPI;
            mmHeight = height * 25.4 / DEFAULT_DPI;
          }
      }
      xf86DrvMsg(pScrn->scrnIndex, X_INFO,
               "Setting screen physical size to %d x %d\n",
               mmWidth, mmHeight);
      /*
       * This is the initial setting of the screen size.
       * We have to pre-set it here, otherwise panning would be adapted
       * to the new screen size.
       */
      pScreen->width  = width;
      pScreen->height = height;
      xf86RandR12ScreenSetSize (pScreen,
                          width,
                          height,
                          mmWidth,
                          mmHeight);
    }

#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(7,0,0,0,0)
    if (xf86RandR12Key == NULL)
      return TRUE;
#endif

    if (randrp->virtualX == -1 || randrp->virtualY == -1)
    {
      randrp->virtualX = pScrn->virtualX;
      randrp->virtualY = pScrn->virtualY;
    }
    xf86CrtcSetScreenSubpixelOrder (pScreen);
#if RANDR_12_INTERFACE
    if (xf86RandR12CreateScreenResources12 (pScreen))
      return TRUE;
#endif
    return TRUE;
}


Bool
xf86RandR12Init (ScreenPtr pScreen)
{
    rrScrPrivPtr  rp;
    XF86RandRInfoPtr    randrp;

#ifdef PANORAMIX
    /* XXX disable RandR when using Xinerama */
    if (!noPanoramiXExtension)
      return TRUE;
#endif

    if (xf86RandR12Generation != serverGeneration)
      xf86RandR12Generation = serverGeneration;

#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(7,0,0,0,0)
    xf86RandR12Key = &xf86RandR12KeyIndex;
#else
    xf86RandR12Index = AllocateScreenPrivateIndex();
#endif

    randrp = xalloc (sizeof (XF86RandRInfoRec));
    if (!randrp)
      return FALSE;

    if (!RRScreenInit(pScreen))
    {
      xfree (randrp);
      return FALSE;
    }
    rp = rrGetScrPriv(pScreen);
    rp->rrGetInfo = xf86RandR12GetInfo;
    rp->rrSetConfig = xf86RandR12SetConfig;

    randrp->virtualX = -1;
    randrp->virtualY = -1;
    randrp->mmWidth = pScreen->mmWidth;
    randrp->mmHeight = pScreen->mmHeight;

    randrp->rotation = RR_Rotate_0; /* initial rotated mode */

    randrp->supported_rotations = RR_Rotate_0;

    randrp->maxX = randrp->maxY = 0;

#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(7,0,0,0,0)
    dixSetPrivate(&pScreen->devPrivates, xf86RandR12Key, randrp);
#else
    pScreen->devPrivates[xf86RandR12Index].ptr = randrp;
#endif

#if RANDR_12_INTERFACE
    if (!xf86RandR12Init12 (pScreen))
      return FALSE;
#endif
    return TRUE;
}

void
xf86RandR12SetRotations (ScreenPtr pScreen, Rotation rotations)
{
    XF86RandRInfoPtr    randrp;
#if RANDR_12_INTERFACE
    ScrnInfoPtr         pScrn = xf86Screens[pScreen->myNum];
    int                 c;
    xf86CrtcConfigPtr   config = XF86_CRTC_CONFIG_PTR(pScrn);
#endif

#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(7,0,0,0,0)
    if (xf86RandR12Key == NULL)
      return;
#endif

    randrp = XF86RANDRINFO(pScreen);
#if RANDR_12_INTERFACE
    for (c = 0; c < config->num_crtc; c++) {
      xf86CrtcPtr    crtc = config->crtc[c];

      RRCrtcSetRotations (crtc->randr_crtc, rotations);
    }
#endif
    randrp->supported_rotations = rotations;
}

void
xf86RandR12SetTransformSupport (ScreenPtr pScreen, Bool transforms)
{
    XF86RandRInfoPtr    randrp;
#if RANDR_13_INTERFACE
    ScrnInfoPtr         pScrn = xf86Screens[pScreen->myNum];
    int                 c;
    xf86CrtcConfigPtr   config = XF86_CRTC_CONFIG_PTR(pScrn);
#endif

#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(7,0,0,0,0)
    if (xf86RandR12Key == NULL)
      return;
#endif

    randrp = XF86RANDRINFO(pScreen);
#if RANDR_13_INTERFACE
    for (c = 0; c < config->num_crtc; c++) {
      xf86CrtcPtr    crtc = config->crtc[c];

      RRCrtcSetTransformSupport (crtc->randr_crtc, transforms);
    }
#endif
}

void
xf86RandR12GetOriginalVirtualSize(ScrnInfoPtr pScrn, int *x, int *y)
{
    ScreenPtr pScreen = screenInfo.screens[pScrn->scrnIndex];

    if (xf86RandR12Generation != serverGeneration ||
      XF86RANDRINFO(pScreen)->virtualX == -1)
    {
      *x = pScrn->virtualX;
      *y = pScrn->virtualY;
    } else {
      XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen);

      *x = randrp->virtualX;
      *y = randrp->virtualY;
    }
}

#if RANDR_12_INTERFACE

#define FLAG_BITS (RR_HSyncPositive | \
               RR_HSyncNegative | \
               RR_VSyncPositive | \
               RR_VSyncNegative | \
               RR_Interlace | \
               RR_DoubleScan | \
               RR_CSync | \
               RR_CSyncPositive | \
               RR_CSyncNegative | \
               RR_HSkewPresent | \
               RR_BCast | \
               RR_PixelMultiplex | \
               RR_DoubleClock | \
               RR_ClockDivideBy2)

static Bool
xf86RandRModeMatches (RRModePtr           randr_mode,
                  DisplayModePtr    mode)
{
#if 0
    if (match_name)
    {
      /* check for same name */
      int   len = strlen (mode->name);
      if (randr_mode->mode.nameLength != len)               return FALSE;
      if (memcmp (randr_mode->name, mode->name, len) != 0)  return FALSE;
    }
#endif
    
    /* check for same timings */
    if (randr_mode->mode.dotClock / 1000 != mode->Clock)    return FALSE;
    if (randr_mode->mode.width        != mode->HDisplay)    return FALSE;
    if (randr_mode->mode.hSyncStart   != mode->HSyncStart)  return FALSE;
    if (randr_mode->mode.hSyncEnd     != mode->HSyncEnd)    return FALSE;
    if (randr_mode->mode.hTotal       != mode->HTotal)          return FALSE;
    if (randr_mode->mode.hSkew        != mode->HSkew)     return FALSE;
    if (randr_mode->mode.height       != mode->VDisplay)    return FALSE;
    if (randr_mode->mode.vSyncStart   != mode->VSyncStart)  return FALSE;
    if (randr_mode->mode.vSyncEnd     != mode->VSyncEnd)    return FALSE;
    if (randr_mode->mode.vTotal       != mode->VTotal)          return FALSE;
    
    /* check for same flags (using only the XF86 valid flag bits) */
    if ((randr_mode->mode.modeFlags & FLAG_BITS) != (mode->Flags & FLAG_BITS))
      return FALSE;
    
    /* everything matches */
    return TRUE;
}

static Bool
xf86RandR12CrtcNotify (RRCrtcPtr    randr_crtc)
{
    ScreenPtr           pScreen = randr_crtc->pScreen;
    ScrnInfoPtr         pScrn = xf86Screens[pScreen->myNum];
    xf86CrtcConfigPtr   config = XF86_CRTC_CONFIG_PTR(pScrn);
    RRModePtr           randr_mode = NULL;
    int                 x;
    int                 y;
    Rotation            rotation;
    int                 numOutputs;
    RROutputPtr         *randr_outputs;
    RROutputPtr         randr_output;
    xf86CrtcPtr         crtc = randr_crtc->devPrivate;
    xf86OutputPtr output;
    int                 i, j;
    DisplayModePtr      mode = &crtc->mode;
    Bool          ret;

    randr_outputs = xalloc(config->num_output * sizeof (RROutputPtr));
    if (!randr_outputs)
      return FALSE;
    x = crtc->x;
    y = crtc->y;
    rotation = crtc->rotation;
    numOutputs = 0;
    randr_mode = NULL;
    for (i = 0; i < config->num_output; i++)
    {
      output = config->output[i];
      if (output->crtc == crtc)
      {
          randr_output = output->randr_output;
          randr_outputs[numOutputs++] = randr_output;
          /*
           * We make copies of modes, so pointer equality 
           * isn't sufficient
           */
          for (j = 0; j < randr_output->numModes + randr_output->numUserModes; j++)
          {
            RRModePtr   m = (j < randr_output->numModes ?
                         randr_output->modes[j] :
                         randr_output->userModes[j-randr_output->numModes]);
                               
            if (xf86RandRModeMatches (m, mode))
            {
                randr_mode = m;
                break;
            }
          }
      }
    }
    ret = RRCrtcNotify (randr_crtc, randr_mode, x, y,
                  rotation, 
                  crtc->transformPresent ? &crtc->transform : NULL,
                  numOutputs, randr_outputs);
    xfree(randr_outputs);
    return ret;
}

/*
 * Convert a RandR mode to a DisplayMode
 */
static void
xf86RandRModeConvert (ScrnInfoPtr   scrn,
                  RRModePtr         randr_mode,
                  DisplayModePtr    mode)
{
    memset(mode, 0, sizeof(DisplayModeRec));
    mode->status = MODE_OK;

    mode->Clock = randr_mode->mode.dotClock / 1000;
    
    mode->HDisplay = randr_mode->mode.width;
    mode->HSyncStart = randr_mode->mode.hSyncStart;
    mode->HSyncEnd = randr_mode->mode.hSyncEnd;
    mode->HTotal = randr_mode->mode.hTotal;
    mode->HSkew = randr_mode->mode.hSkew;
    
    mode->VDisplay = randr_mode->mode.height;
    mode->VSyncStart = randr_mode->mode.vSyncStart;
    mode->VSyncEnd = randr_mode->mode.vSyncEnd;
    mode->VTotal = randr_mode->mode.vTotal;
    mode->VScan = 0;

    mode->Flags = randr_mode->mode.modeFlags & FLAG_BITS;

    xf86SetModeCrtc (mode, scrn->adjustFlags);
}

static Bool
xf86RandR12CrtcSet (ScreenPtr     pScreen,
                RRCrtcPtr         randr_crtc,
                RRModePtr         randr_mode,
                int               x,
                int               y,
                Rotation          rotation,
                int               num_randr_outputs,
                RROutputPtr       *randr_outputs)
{
    XF86RandRInfoPtr    randrp = XF86RANDRINFO(pScreen);
    ScrnInfoPtr         pScrn = xf86Screens[pScreen->myNum];
    xf86CrtcConfigPtr   config = XF86_CRTC_CONFIG_PTR(pScrn);
    xf86CrtcPtr         crtc = randr_crtc->devPrivate;
    RRTransformPtr      transform;
    Bool          changed = FALSE;
    int                 o, ro;
    xf86CrtcPtr         *save_crtcs;
    Bool          save_enabled = crtc->enabled;

    if (!crtc->scrn->vtSema)
      return FALSE;

    save_crtcs = xalloc(config->num_output * sizeof (xf86CrtcPtr));
    if ((randr_mode != NULL) != crtc->enabled)
      changed = TRUE;
    else if (randr_mode && !xf86RandRModeMatches (randr_mode, &crtc->mode))
      changed = TRUE;
    
    if (rotation != crtc->rotation)
      changed = TRUE;

    transform = RRCrtcGetTransform (randr_crtc);
    if ((transform != NULL) != crtc->transformPresent)
      changed = TRUE;
    else if (transform && memcmp (&transform->transform, &crtc->transform.transform,
                          sizeof (transform->transform)) != 0)
      changed = TRUE;

    if (x != crtc->x || y != crtc->y)
      changed = TRUE;
    for (o = 0; o < config->num_output; o++) 
    {
      xf86OutputPtr  output = config->output[o];
      xf86CrtcPtr    new_crtc;

      save_crtcs[o] = output->crtc;
      
      if (output->crtc == crtc)
          new_crtc = NULL;
      else
          new_crtc = output->crtc;
      for (ro = 0; ro < num_randr_outputs; ro++) 
          if (output->randr_output == randr_outputs[ro])
          {
            new_crtc = crtc;
            break;
          }
      if (new_crtc != output->crtc)
      {
          changed = TRUE;
          output->crtc = new_crtc;
      }
    }
    for (ro = 0; ro < num_randr_outputs; ro++) 
        if (randr_outputs[ro]->pendingProperties)
          changed = TRUE;

    /* XXX need device-independent mode setting code through an API */
    if (changed)
    {
      crtc->enabled = randr_mode != NULL;

      if (randr_mode)
      {
          DisplayModeRec  mode;
          RRTransformPtr  transform = RRCrtcGetTransform (randr_crtc);

          xf86RandRModeConvert (pScrn, randr_mode, &mode);
          if (!xf86CrtcSetModeTransform (crtc, &mode, rotation, transform, x, y))
          {
            crtc->enabled = save_enabled;
            for (o = 0; o < config->num_output; o++)
            {
                xf86OutputPtr output = config->output[o];
                output->crtc = save_crtcs[o];
            }
            xfree(save_crtcs);
            return FALSE;
          }
          xf86RandR13VerifyPanningArea (crtc, pScreen->width, pScreen->height);
          xf86RandR13Pan (crtc, randrp->pointerX, randrp->pointerY);
          /*
           * Save the last successful setting for EnterVT
           */
          crtc->desiredMode = mode;
          crtc->desiredRotation = rotation;
          if (transform) {
            crtc->desiredTransform = *transform;
            crtc->desiredTransformPresent = TRUE;
          } else
            crtc->desiredTransformPresent = FALSE;

          crtc->desiredX = x;
          crtc->desiredY = y;
      }
      xf86DisableUnusedFunctions (pScrn);
    }
    xfree(save_crtcs);
    return xf86RandR12CrtcNotify (randr_crtc);
}

static Bool
xf86RandR12CrtcSetGamma (ScreenPtr    pScreen,
                   RRCrtcPtr    randr_crtc)
{
    xf86CrtcPtr         crtc = randr_crtc->devPrivate;

    if (crtc->funcs->gamma_set == NULL)
      return FALSE;

    if (!crtc->scrn->vtSema)
      return TRUE;

    /* Realloc local gamma if needed. */
    if (randr_crtc->gammaSize != crtc->gamma_size) {
        CARD16 *tmp_ptr;
        tmp_ptr = realloc(crtc->gamma_red, 3 * crtc->gamma_size * sizeof (CARD16));
        if (!tmp_ptr)
            return FALSE;
        crtc->gamma_red = tmp_ptr;
        crtc->gamma_green = crtc->gamma_red + crtc->gamma_size;
        crtc->gamma_blue = crtc->gamma_green + crtc->gamma_size;
    }

    crtc->gamma_size = randr_crtc->gammaSize;
    memcpy (crtc->gamma_red, randr_crtc->gammaRed, crtc->gamma_size * sizeof (CARD16));
    memcpy (crtc->gamma_green, randr_crtc->gammaGreen, crtc->gamma_size * sizeof (CARD16));
    memcpy (crtc->gamma_blue, randr_crtc->gammaBlue, crtc->gamma_size * sizeof (CARD16));

    /* Only set it when the crtc is actually running.
     * Otherwise it will be set when it's activated.
     */
    if (crtc->active)
      crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green,
                                    crtc->gamma_blue, crtc->gamma_size);

    return TRUE;
}

static Bool
xf86RandR12CrtcGetGamma (ScreenPtr    pScreen,
                   RRCrtcPtr    randr_crtc)
{
    xf86CrtcPtr crtc = randr_crtc->devPrivate;

    if (!crtc->gamma_size)
        return FALSE;

    if (!crtc->gamma_red || !crtc->gamma_green || !crtc->gamma_blue)
        return FALSE;

    /* Realloc randr gamma if needed. */
    if (randr_crtc->gammaSize != crtc->gamma_size) {
        CARD16 *tmp_ptr;
        tmp_ptr = realloc(randr_crtc->gammaRed, 3 * crtc->gamma_size * sizeof (CARD16));
        if (!tmp_ptr)
            return FALSE;
        randr_crtc->gammaRed = tmp_ptr;
        randr_crtc->gammaGreen = randr_crtc->gammaRed + crtc->gamma_size;
        randr_crtc->gammaBlue = randr_crtc->gammaGreen + crtc->gamma_size;
    }
    randr_crtc->gammaSize = crtc->gamma_size;
    memcpy (randr_crtc->gammaRed, crtc->gamma_red, crtc->gamma_size * sizeof (CARD16));
    memcpy (randr_crtc->gammaGreen, crtc->gamma_green, crtc->gamma_size * sizeof (CARD16));
    memcpy (randr_crtc->gammaBlue, crtc->gamma_blue, crtc->gamma_size * sizeof (CARD16));

    return TRUE;
}

static Bool
xf86RandR12OutputSetProperty (ScreenPtr pScreen,
                        RROutputPtr randr_output,
                        Atom property,
                        RRPropertyValuePtr value)
{
    xf86OutputPtr output = randr_output->devPrivate;

    /* If we don't have any property handler, then we don't care what the
     * user is setting properties to.
     */
    if (output->funcs->set_property == NULL)
      return TRUE;

    /*
     * This function gets called even when vtSema is FALSE, as
     * drivers will need to remember the correct value to apply
     * when the VT switch occurs
     */
    return output->funcs->set_property(output, property, value);
}

static Bool
xf86RandR13OutputGetProperty (ScreenPtr pScreen,
                        RROutputPtr randr_output,
                        Atom property)
{
    xf86OutputPtr output = randr_output->devPrivate;

    if (output->funcs->get_property == NULL)
      return TRUE;

    /* Should be safe even w/o vtSema */
    return output->funcs->get_property(output, property);
}

static Bool
xf86RandR12OutputValidateMode (ScreenPtr    pScreen,
                         RROutputPtr  randr_output,
                         RRModePtr    randr_mode)
{
    ScrnInfoPtr       pScrn = xf86Screens[pScreen->myNum];
    xf86OutputPtr   output = randr_output->devPrivate;
    DisplayModeRec  mode;

    xf86RandRModeConvert (pScrn, randr_mode, &mode);
    /*
     * This function may be called when vtSema is FALSE, so
     * the underlying function must either avoid touching the hardware
     * or return FALSE when vtSema is FALSE
     */
    if (output->funcs->mode_valid (output, &mode) != MODE_OK)
      return FALSE;
    return TRUE;
}

static void
xf86RandR12ModeDestroy (ScreenPtr pScreen, RRModePtr randr_mode)
{
}

/**
 * Given a list of xf86 modes and a RandR Output object, construct
 * RandR modes and assign them to the output
 */
static Bool
xf86RROutputSetModes (RROutputPtr randr_output, DisplayModePtr modes)
{
    DisplayModePtr  mode;
    RRModePtr         *rrmodes = NULL;
    int               nmode = 0;
    int               npreferred = 0;
    Bool        ret = TRUE;
    int               pref;

    for (mode = modes; mode; mode = mode->next)
      nmode++;

    if (nmode) {
      rrmodes = xalloc (nmode * sizeof (RRModePtr));
      
      if (!rrmodes)
          return FALSE;
      nmode = 0;

      for (pref = 1; pref >= 0; pref--) {
          for (mode = modes; mode; mode = mode->next) {
            if ((pref != 0) == ((mode->type & M_T_PREFERRED) != 0)) {
                xRRModeInfo         modeInfo;
                RRModePtr           rrmode;
                
                modeInfo.nameLength = strlen (mode->name);
                modeInfo.width = mode->HDisplay;
                modeInfo.dotClock = mode->Clock * 1000;
                modeInfo.hSyncStart = mode->HSyncStart;
                modeInfo.hSyncEnd = mode->HSyncEnd;
                modeInfo.hTotal = mode->HTotal;
                modeInfo.hSkew = mode->HSkew;

                modeInfo.height = mode->VDisplay;
                modeInfo.vSyncStart = mode->VSyncStart;
                modeInfo.vSyncEnd = mode->VSyncEnd;
                modeInfo.vTotal = mode->VTotal;
                modeInfo.modeFlags = mode->Flags;

                rrmode = RRModeGet (&modeInfo, mode->name);
                if (rrmode) {
                  rrmodes[nmode++] = rrmode;
                  npreferred += pref;
                }
            }
          }
      }
    }
    
    ret = RROutputSetModes (randr_output, rrmodes, nmode, npreferred);
    xfree (rrmodes);
    return ret;
}

/*
 * Mirror the current mode configuration to RandR
 */
static Bool
xf86RandR12SetInfo12 (ScreenPtr pScreen)
{
    ScrnInfoPtr         pScrn = xf86Screens[pScreen->myNum];
    xf86CrtcConfigPtr   config = XF86_CRTC_CONFIG_PTR(pScrn);
    RROutputPtr         *clones;
    RRCrtcPtr           *crtcs;
    int                 ncrtc;
    int                 o, c, l;
    RRCrtcPtr           randr_crtc;
    int                 nclone;
    
    clones = xalloc(config->num_output * sizeof (RROutputPtr));
    crtcs = xalloc (config->num_crtc * sizeof (RRCrtcPtr));
    for (o = 0; o < config->num_output; o++)
    {
      xf86OutputPtr     output = config->output[o];
      
      ncrtc = 0;
      for (c = 0; c < config->num_crtc; c++)
          if (output->possible_crtcs & (1 << c))
            crtcs[ncrtc++] = config->crtc[c]->randr_crtc;

      if (output->crtc)
          randr_crtc = output->crtc->randr_crtc;
      else
          randr_crtc = NULL;

      if (!RROutputSetCrtcs (output->randr_output, crtcs, ncrtc))
      {
          xfree (crtcs);
          xfree (clones);
          return FALSE;
      }

      RROutputSetPhysicalSize(output->randr_output, 
                        output->mm_width,
                        output->mm_height);
      xf86RROutputSetModes (output->randr_output, output->probed_modes);

      switch (output->status) {
      case XF86OutputStatusConnected:
          RROutputSetConnection (output->randr_output, RR_Connected);
          break;
      case XF86OutputStatusDisconnected:
          RROutputSetConnection (output->randr_output, RR_Disconnected);
          break;
      case XF86OutputStatusUnknown:
          RROutputSetConnection (output->randr_output, RR_UnknownConnection);
          break;
      }

      RROutputSetSubpixelOrder (output->randr_output, output->subpixel_order);

      /*
       * Valid clones
       */
      nclone = 0;
      for (l = 0; l < config->num_output; l++)
      {
          xf86OutputPtr     clone = config->output[l];
          
          if (l != o && (output->possible_clones & (1 << l)))
            clones[nclone++] = clone->randr_output;
      }
      if (!RROutputSetClones (output->randr_output, clones, nclone))
      {
          xfree (crtcs);
          xfree (clones);
          return FALSE;
      }
    }
    xfree (crtcs);
    xfree (clones);
    return TRUE;
}



/*
 * Query the hardware for the current state, then mirror
 * that to RandR
 */
static Bool
xf86RandR12GetInfo12 (ScreenPtr pScreen, Rotation *rotations)
{
    ScrnInfoPtr         pScrn = xf86Screens[pScreen->myNum];

    if (!pScrn->vtSema)
      return TRUE;
    xf86ProbeOutputModes (pScrn, 0, 0);
    xf86SetScrnInfoModes (pScrn);
#ifdef XFreeXDGA
    xf86DiDGAReInit (pScreen);
#endif
    return xf86RandR12SetInfo12 (pScreen);
}

static Bool
xf86RandR12CreateObjects12 (ScreenPtr pScreen)
{
    ScrnInfoPtr         pScrn = xf86Screens[pScreen->myNum];
    xf86CrtcConfigPtr   config = XF86_CRTC_CONFIG_PTR(pScrn);
    int                 c;
    int                 o;
    
    if (!RRInit ())
      return FALSE;

    /*
     * Configure crtcs
     */
    for (c = 0; c < config->num_crtc; c++)
    {
      xf86CrtcPtr    crtc = config->crtc[c];
      
      crtc->randr_crtc = RRCrtcCreate (pScreen, crtc);
      RRCrtcGammaSetSize (crtc->randr_crtc, 256);
    }
    /*
     * Configure outputs
     */
    for (o = 0; o < config->num_output; o++)
    {
      xf86OutputPtr     output = config->output[o];

      output->randr_output = RROutputCreate (pScreen, output->name, 
                                     strlen (output->name),
                                     output);

      if (output->funcs->create_resources != NULL)
          output->funcs->create_resources(output);
      RRPostPendingProperties (output->randr_output);
    }
    return TRUE;
}

static Bool
xf86RandR12CreateScreenResources12 (ScreenPtr pScreen)
{
    int                 c;
    ScrnInfoPtr         pScrn = xf86Screens[pScreen->myNum];
    xf86CrtcConfigPtr   config = XF86_CRTC_CONFIG_PTR(pScrn);

#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(7,0,0,0,0)
    if (xf86RandR12Key == NULL)
      return TRUE;
#endif

    for (c = 0; c < config->num_crtc; c++)
        xf86RandR12CrtcNotify (config->crtc[c]->randr_crtc);
    
    RRScreenSetSizeRange (pScreen, config->minWidth, config->minHeight,
                    config->maxWidth, config->maxHeight);
    return TRUE;
}

/*
 * Something happened within the screen configuration due
 * to DGA, VidMode or hot key. Tell RandR
 */

void
xf86RandR12TellChanged (ScreenPtr pScreen)
{
    ScrnInfoPtr         pScrn = xf86Screens[pScreen->myNum];
    xf86CrtcConfigPtr   config = XF86_CRTC_CONFIG_PTR(pScrn);
    int                 c;

#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(7,0,0,0,0)
    if (xf86RandR12Key == NULL)
      return;
#else
    if (!XF86RANDRINFO(pScreen))
      return;
#endif

    xf86RandR12SetInfo12 (pScreen);
    for (c = 0; c < config->num_crtc; c++)
      xf86RandR12CrtcNotify (config->crtc[c]->randr_crtc);

    RRTellChanged (pScreen);
}

static void
xf86RandR12PointerMoved (int scrnIndex, int x, int y)
{
    ScreenPtr           pScreen = screenInfo.screens[scrnIndex];
    ScrnInfoPtr         pScrn   = XF86SCRNINFO(pScreen);
    xf86CrtcConfigPtr   config  = XF86_CRTC_CONFIG_PTR(pScrn);
    XF86RandRInfoPtr    randrp  = XF86RANDRINFO(pScreen);
    int c;

    randrp->pointerX = x;
    randrp->pointerY = y;
    for (c = 0; c < config->num_crtc; c++)
      xf86RandR13Pan (config->crtc[c], x, y);
}

static Bool
xf86RandR13GetPanning (ScreenPtr           pScreen,
                   RRCrtcPtr           randr_crtc,
                   BoxPtr              totalArea,
                   BoxPtr              trackingArea,
                   INT16               *border)
{
    xf86CrtcPtr         crtc = randr_crtc->devPrivate;

    if (crtc->version < 2)
      return FALSE;
    if (totalArea)
      memcpy (totalArea,    &crtc->panningTotalArea,    sizeof(BoxRec));
    if (trackingArea)
      memcpy (trackingArea, &crtc->panningTrackingArea, sizeof(BoxRec));
    if (border)
      memcpy (border,        crtc->panningBorder,       4*sizeof(INT16));

    return TRUE;
}

static Bool
xf86RandR13SetPanning (ScreenPtr           pScreen,
                   RRCrtcPtr           randr_crtc,
                   BoxPtr              totalArea,
                   BoxPtr              trackingArea,
                   INT16               *border)
{
    XF86RandRInfoPtr    randrp  = XF86RANDRINFO(pScreen);
    xf86CrtcPtr         crtc = randr_crtc->devPrivate;
    BoxRec        oldTotalArea;
    BoxRec        oldTrackingArea;
    INT16         oldBorder[4];


    if (crtc->version < 2)
      return FALSE;

    memcpy (&oldTotalArea,    &crtc->panningTotalArea,    sizeof(BoxRec));
    memcpy (&oldTrackingArea, &crtc->panningTrackingArea, sizeof(BoxRec));
    memcpy (oldBorder,         crtc->panningBorder,       4*sizeof(INT16));

    if (totalArea)
      memcpy (&crtc->panningTotalArea, totalArea, sizeof(BoxRec));
    if (trackingArea)
      memcpy (&crtc->panningTrackingArea, trackingArea, sizeof(BoxRec));
    if (border)
      memcpy (crtc->panningBorder, border, 4*sizeof(INT16));

    if (xf86RandR13VerifyPanningArea (crtc, pScreen->width, pScreen->height)) {
      xf86RandR13Pan (crtc, randrp->pointerX, randrp->pointerY);
      return TRUE;
    } else {
      /* Restore old settings */
      memcpy (&crtc->panningTotalArea,    &oldTotalArea,    sizeof(BoxRec));
      memcpy (&crtc->panningTrackingArea, &oldTrackingArea, sizeof(BoxRec));
      memcpy (crtc->panningBorder,         oldBorder,       4*sizeof(INT16));
      return FALSE;
    }
}

static Bool
xf86RandR12Init12 (ScreenPtr pScreen)
{
    ScrnInfoPtr         pScrn = xf86Screens[pScreen->myNum];
    rrScrPrivPtr  rp = rrGetScrPriv(pScreen);

    rp->rrGetInfo = xf86RandR12GetInfo12;
    rp->rrScreenSetSize = xf86RandR12ScreenSetSize;
    rp->rrCrtcSet = xf86RandR12CrtcSet;
    rp->rrCrtcSetGamma = xf86RandR12CrtcSetGamma;
    rp->rrCrtcGetGamma = xf86RandR12CrtcGetGamma;
    rp->rrOutputSetProperty = xf86RandR12OutputSetProperty;
    rp->rrOutputValidateMode = xf86RandR12OutputValidateMode;
#if RANDR_13_INTERFACE
    rp->rrOutputGetProperty = xf86RandR13OutputGetProperty;
    rp->rrGetPanning = xf86RandR13GetPanning;
    rp->rrSetPanning = xf86RandR13SetPanning;
#endif
    rp->rrModeDestroy = xf86RandR12ModeDestroy;
    rp->rrSetConfig = NULL;
    pScrn->PointerMoved = xf86RandR12PointerMoved;
    if (!xf86RandR12CreateObjects12 (pScreen))
      return FALSE;

    /*
     * Configure output modes
     */
    if (!xf86RandR12SetInfo12 (pScreen))
      return FALSE;
    return TRUE;
}

#endif

Bool
xf86RandR12PreInit (ScrnInfoPtr pScrn)
{
    return TRUE;
}

Generated by  Doxygen 1.6.0   Back to index