aboutsummaryrefslogtreecommitdiff
path: root/xorg-server/randr
diff options
context:
space:
mode:
Diffstat (limited to 'xorg-server/randr')
-rw-r--r--xorg-server/randr/rrcrtc.c3012
1 files changed, 1506 insertions, 1506 deletions
diff --git a/xorg-server/randr/rrcrtc.c b/xorg-server/randr/rrcrtc.c
index a846ad3d1..0437795c4 100644
--- a/xorg-server/randr/rrcrtc.c
+++ b/xorg-server/randr/rrcrtc.c
@@ -1,1506 +1,1506 @@
-/*
- * Copyright © 2006 Keith Packard
- * Copyright 2010 Red Hat, 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.
- */
-
-#include "randrstr.h"
-#include "swaprep.h"
-#include "mipointer.h"
-
-RESTYPE RRCrtcType;
-
-/*
- * Notify the CRTC of some change
- */
-void
-RRCrtcChanged (RRCrtcPtr crtc, Bool layoutChanged)
-{
- ScreenPtr pScreen = crtc->pScreen;
-
- crtc->changed = TRUE;
- if (pScreen)
- {
- rrScrPriv(pScreen);
-
- pScrPriv->changed = TRUE;
- /*
- * Send ConfigureNotify on any layout change
- */
- if (layoutChanged)
- pScrPriv->layoutChanged = TRUE;
- }
-}
-
-/*
- * Create a CRTC
- */
-RRCrtcPtr
-RRCrtcCreate (ScreenPtr pScreen, void *devPrivate)
-{
- RRCrtcPtr crtc;
- RRCrtcPtr *crtcs;
- rrScrPrivPtr pScrPriv;
-
- if (!RRInit())
- return NULL;
-
- pScrPriv = rrGetScrPriv(pScreen);
-
- /* make space for the crtc pointer */
- if (pScrPriv->numCrtcs)
- crtcs = realloc(pScrPriv->crtcs,
- (pScrPriv->numCrtcs + 1) * sizeof (RRCrtcPtr));
- else
- crtcs = malloc(sizeof (RRCrtcPtr));
- if (!crtcs)
- return FALSE;
- pScrPriv->crtcs = crtcs;
-
- crtc = calloc(1, sizeof (RRCrtcRec));
- if (!crtc)
- return NULL;
- crtc->id = FakeClientID (0);
- crtc->pScreen = pScreen;
- crtc->mode = NULL;
- crtc->x = 0;
- crtc->y = 0;
- crtc->rotation = RR_Rotate_0;
- crtc->rotations = RR_Rotate_0;
- crtc->outputs = NULL;
- crtc->numOutputs = 0;
- crtc->gammaSize = 0;
- crtc->gammaRed = crtc->gammaBlue = crtc->gammaGreen = NULL;
- crtc->changed = FALSE;
- crtc->devPrivate = devPrivate;
- RRTransformInit (&crtc->client_pending_transform);
- RRTransformInit (&crtc->client_current_transform);
- pixman_transform_init_identity (&crtc->transform);
- pixman_f_transform_init_identity (&crtc->f_transform);
- pixman_f_transform_init_identity (&crtc->f_inverse);
-
- if (!AddResource (crtc->id, RRCrtcType, (pointer) crtc))
- return NULL;
-
- /* attach the screen and crtc together */
- crtc->pScreen = pScreen;
- pScrPriv->crtcs[pScrPriv->numCrtcs++] = crtc;
-
- return crtc;
-}
-
-/*
- * Set the allowed rotations on a CRTC
- */
-void
-RRCrtcSetRotations (RRCrtcPtr crtc, Rotation rotations)
-{
- crtc->rotations = rotations;
-}
-
-/*
- * Set whether transforms are allowed on a CRTC
- */
-void
-RRCrtcSetTransformSupport (RRCrtcPtr crtc, Bool transforms)
-{
- crtc->transforms = transforms;
-}
-
-/*
- * Notify the extension that the Crtc has been reconfigured,
- * the driver calls this whenever it has updated the mode
- */
-Bool
-RRCrtcNotify (RRCrtcPtr crtc,
- RRModePtr mode,
- int x,
- int y,
- Rotation rotation,
- RRTransformPtr transform,
- int numOutputs,
- RROutputPtr *outputs)
-{
- int i, j;
-
- /*
- * Check to see if any of the new outputs were
- * not in the old list and mark them as changed
- */
- for (i = 0; i < numOutputs; i++)
- {
- for (j = 0; j < crtc->numOutputs; j++)
- if (outputs[i] == crtc->outputs[j])
- break;
- if (j == crtc->numOutputs)
- {
- outputs[i]->crtc = crtc;
- RROutputChanged (outputs[i], FALSE);
- RRCrtcChanged (crtc, FALSE);
- }
- }
- /*
- * Check to see if any of the old outputs are
- * not in the new list and mark them as changed
- */
- for (j = 0; j < crtc->numOutputs; j++)
- {
- for (i = 0; i < numOutputs; i++)
- if (outputs[i] == crtc->outputs[j])
- break;
- if (i == numOutputs)
- {
- if (crtc->outputs[j]->crtc == crtc)
- crtc->outputs[j]->crtc = NULL;
- RROutputChanged (crtc->outputs[j], FALSE);
- RRCrtcChanged (crtc, FALSE);
- }
- }
- /*
- * Reallocate the crtc output array if necessary
- */
- if (numOutputs != crtc->numOutputs)
- {
- RROutputPtr *newoutputs;
-
- if (numOutputs)
- {
- if (crtc->numOutputs)
- newoutputs = realloc(crtc->outputs,
- numOutputs * sizeof (RROutputPtr));
- else
- newoutputs = malloc(numOutputs * sizeof (RROutputPtr));
- if (!newoutputs)
- return FALSE;
- }
- else
- {
- free(crtc->outputs);
- newoutputs = NULL;
- }
- crtc->outputs = newoutputs;
- crtc->numOutputs = numOutputs;
- }
- /*
- * Copy the new list of outputs into the crtc
- */
- memcpy (crtc->outputs, outputs, numOutputs * sizeof (RROutputPtr));
- /*
- * Update remaining crtc fields
- */
- if (mode != crtc->mode)
- {
- if (crtc->mode)
- RRModeDestroy (crtc->mode);
- crtc->mode = mode;
- if (mode != NULL)
- mode->refcnt++;
- RRCrtcChanged (crtc, TRUE);
- }
- if (x != crtc->x)
- {
- crtc->x = x;
- RRCrtcChanged (crtc, TRUE);
- }
- if (y != crtc->y)
- {
- crtc->y = y;
- RRCrtcChanged (crtc, TRUE);
- }
- if (rotation != crtc->rotation)
- {
- crtc->rotation = rotation;
- RRCrtcChanged (crtc, TRUE);
- }
- if (!RRTransformEqual (transform, &crtc->client_current_transform)) {
- RRTransformCopy (&crtc->client_current_transform, transform);
- RRCrtcChanged (crtc, TRUE);
- }
- if (crtc->changed && mode)
- {
- RRTransformCompute (x, y,
- mode->mode.width, mode->mode.height,
- rotation,
- &crtc->client_current_transform,
- &crtc->transform, &crtc->f_transform,
- &crtc->f_inverse);
- }
- return TRUE;
-}
-
-void
-RRDeliverCrtcEvent (ClientPtr client, WindowPtr pWin, RRCrtcPtr crtc)
-{
- ScreenPtr pScreen = pWin->drawable.pScreen;
- rrScrPriv (pScreen);
- xRRCrtcChangeNotifyEvent ce;
- RRModePtr mode = crtc->mode;
-
- ce.type = RRNotify + RREventBase;
- ce.subCode = RRNotify_CrtcChange;
- ce.timestamp = pScrPriv->lastSetTime.milliseconds;
- ce.window = pWin->drawable.id;
- ce.crtc = crtc->id;
- ce.rotation = crtc->rotation;
- if (mode)
- {
- ce.mode = mode->mode.id;
- ce.x = crtc->x;
- ce.y = crtc->y;
- ce.width = mode->mode.width;
- ce.height = mode->mode.height;
- }
- else
- {
- ce.mode = None;
- ce.x = 0;
- ce.y = 0;
- ce.width = 0;
- ce.height = 0;
- }
- WriteEventsToClient (client, 1, (xEvent *) &ce);
-}
-
-static Bool
-RRCrtcPendingProperties (RRCrtcPtr crtc)
-{
- ScreenPtr pScreen = crtc->pScreen;
- rrScrPriv(pScreen);
- int o;
-
- for (o = 0; o < pScrPriv->numOutputs; o++)
- {
- RROutputPtr output = pScrPriv->outputs[o];
- if (output->crtc == crtc && output->pendingProperties)
- return TRUE;
- }
- return FALSE;
-}
-
-static void
-crtc_bounds(RRCrtcPtr crtc, int *left, int *right, int *top, int *bottom)
-{
- *left = crtc->x;
- *top = crtc->y;
-
- switch (crtc->rotation) {
- case RR_Rotate_0:
- case RR_Rotate_180:
- default:
- *right = crtc->x + crtc->mode->mode.width;
- *bottom = crtc->y + crtc->mode->mode.height;
- return;
- case RR_Rotate_90:
- case RR_Rotate_270:
- *right = crtc->x + crtc->mode->mode.height;
- *bottom = crtc->y + crtc->mode->mode.width;
- return;
- }
-}
-
-/* overlapping counts as adjacent */
-static Bool
-crtcs_adjacent(const RRCrtcPtr a, const RRCrtcPtr b)
-{
- /* left, right, top, bottom... */
- int al, ar, at, ab;
- int bl, br, bt, bb;
- int cl, cr, ct, cb; /* the overlap, if any */
-
- crtc_bounds(a, &al, &ar, &at, &ab);
- crtc_bounds(b, &bl, &br, &bt, &bb);
-
- cl = max(al, bl);
- cr = min(ar, br);
- ct = max(at, bt);
- cb = min(ab, bb);
-
- return (cl <= cr) && (ct <= cb);
-}
-
-/* Depth-first search and mark all CRTCs reachable from cur */
-static void
-mark_crtcs (rrScrPrivPtr pScrPriv, int *reachable, int cur)
-{
- int i;
- reachable[cur] = TRUE;
- for (i = 0; i < pScrPriv->numCrtcs; ++i) {
- if (reachable[i] || !pScrPriv->crtcs[i]->mode)
- continue;
- if (crtcs_adjacent(pScrPriv->crtcs[cur], pScrPriv->crtcs[i]))
- mark_crtcs(pScrPriv, reachable, i);
- }
-}
-
-static void
-RRComputeContiguity (ScreenPtr pScreen)
-{
- rrScrPriv(pScreen);
- Bool discontiguous = TRUE;
- int i, n = pScrPriv->numCrtcs;
-
- int *reachable = calloc(n, sizeof(int));
- if (!reachable)
- goto out;
-
- /* Find first enabled CRTC and start search for reachable CRTCs from it */
- for (i = 0; i < n; ++i) {
- if (pScrPriv->crtcs[i]->mode) {
- mark_crtcs(pScrPriv, reachable, i);
- break;
- }
- }
-
- /* Check that all enabled CRTCs were marked as reachable */
- for (i = 0; i < n; ++i)
- if (pScrPriv->crtcs[i]->mode && !reachable[i])
- goto out;
-
- discontiguous = FALSE;
-
-out:
- free(reachable);
- pScrPriv->discontiguous = discontiguous;
-}
-
-/*
- * Request that the Crtc be reconfigured
- */
-Bool
-RRCrtcSet (RRCrtcPtr crtc,
- RRModePtr mode,
- int x,
- int y,
- Rotation rotation,
- int numOutputs,
- RROutputPtr *outputs)
-{
- ScreenPtr pScreen = crtc->pScreen;
- Bool ret = FALSE;
- Bool recompute = TRUE;
- rrScrPriv(pScreen);
-
- /* See if nothing changed */
- if (crtc->mode == mode &&
- crtc->x == x &&
- crtc->y == y &&
- crtc->rotation == rotation &&
- crtc->numOutputs == numOutputs &&
- !memcmp (crtc->outputs, outputs, numOutputs * sizeof (RROutputPtr)) &&
- !RRCrtcPendingProperties (crtc) &&
- !RRCrtcPendingTransform (crtc))
- {
- recompute = FALSE;
- ret = TRUE;
- }
- else
- {
-#if RANDR_12_INTERFACE
- if (pScrPriv->rrCrtcSet)
- {
- ret = (*pScrPriv->rrCrtcSet) (pScreen, crtc, mode, x, y,
- rotation, numOutputs, outputs);
- }
- else
-#endif
- {
-#if RANDR_10_INTERFACE
- if (pScrPriv->rrSetConfig)
- {
- RRScreenSize size;
- RRScreenRate rate;
-
- if (!mode)
- {
- RRCrtcNotify (crtc, NULL, x, y, rotation, NULL, 0, NULL);
- ret = TRUE;
- }
- else
- {
- size.width = mode->mode.width;
- size.height = mode->mode.height;
- if (outputs[0]->mmWidth && outputs[0]->mmHeight)
- {
- size.mmWidth = outputs[0]->mmWidth;
- size.mmHeight = outputs[0]->mmHeight;
- }
- else
- {
- size.mmWidth = pScreen->mmWidth;
- size.mmHeight = pScreen->mmHeight;
- }
- size.nRates = 1;
- rate.rate = RRVerticalRefresh (&mode->mode);
- size.pRates = &rate;
- ret = (*pScrPriv->rrSetConfig) (pScreen, rotation, rate.rate, &size);
- /*
- * Old 1.0 interface tied screen size to mode size
- */
- if (ret)
- {
- RRCrtcNotify (crtc, mode, x, y, rotation, NULL, 1, outputs);
- RRScreenSizeNotify (pScreen);
- }
- }
- }
-#endif
- }
- if (ret)
- {
- int o;
- RRTellChanged (pScreen);
-
- for (o = 0; o < numOutputs; o++)
- RRPostPendingProperties (outputs[o]);
- }
- }
-
- if (recompute)
- RRComputeContiguity(pScreen);
-
- return ret;
-}
-
-/*
- * Return crtc transform
- */
-RRTransformPtr
-RRCrtcGetTransform (RRCrtcPtr crtc)
-{
- RRTransformPtr transform = &crtc->client_pending_transform;
-
- if (pixman_transform_is_identity (&transform->transform))
- return NULL;
- return transform;
-}
-
-/*
- * Check whether the pending and current transforms are the same
- */
-Bool
-RRCrtcPendingTransform (RRCrtcPtr crtc)
-{
- return memcmp (&crtc->client_current_transform.transform,
- &crtc->client_pending_transform.transform,
- sizeof (PictTransform)) != 0;
-}
-
-/*
- * Destroy a Crtc at shutdown
- */
-void
-RRCrtcDestroy (RRCrtcPtr crtc)
-{
- FreeResource (crtc->id, 0);
-}
-
-static int
-RRCrtcDestroyResource (pointer value, XID pid)
-{
- RRCrtcPtr crtc = (RRCrtcPtr) value;
- ScreenPtr pScreen = crtc->pScreen;
-
- if (pScreen)
- {
- rrScrPriv(pScreen);
- int i;
-
- for (i = 0; i < pScrPriv->numCrtcs; i++)
- {
- if (pScrPriv->crtcs[i] == crtc)
- {
- memmove (pScrPriv->crtcs + i, pScrPriv->crtcs + i + 1,
- (pScrPriv->numCrtcs - (i + 1)) * sizeof (RRCrtcPtr));
- --pScrPriv->numCrtcs;
- break;
- }
- }
- }
- free(crtc->gammaRed);
- if (crtc->mode)
- RRModeDestroy (crtc->mode);
- free(crtc);
- return 1;
-}
-
-/*
- * Request that the Crtc gamma be changed
- */
-
-Bool
-RRCrtcGammaSet (RRCrtcPtr crtc,
- CARD16 *red,
- CARD16 *green,
- CARD16 *blue)
-{
- Bool ret = TRUE;
-#if RANDR_12_INTERFACE
- ScreenPtr pScreen = crtc->pScreen;
-#endif
-
- memcpy (crtc->gammaRed, red, crtc->gammaSize * sizeof (CARD16));
- memcpy (crtc->gammaGreen, green, crtc->gammaSize * sizeof (CARD16));
- memcpy (crtc->gammaBlue, blue, crtc->gammaSize * sizeof (CARD16));
-#if RANDR_12_INTERFACE
- if (pScreen)
- {
- rrScrPriv(pScreen);
- if (pScrPriv->rrCrtcSetGamma)
- ret = (*pScrPriv->rrCrtcSetGamma) (pScreen, crtc);
- }
-#endif
- return ret;
-}
-
-/*
- * Request current gamma back from the DDX (if possible).
- * This includes gamma size.
- */
-Bool
-RRCrtcGammaGet(RRCrtcPtr crtc)
-{
- Bool ret = TRUE;
-#if RANDR_12_INTERFACE
- ScreenPtr pScreen = crtc->pScreen;
-#endif
-
-#if RANDR_12_INTERFACE
- if (pScreen)
- {
- rrScrPriv(pScreen);
- if (pScrPriv->rrCrtcGetGamma)
- ret = (*pScrPriv->rrCrtcGetGamma) (pScreen, crtc);
- }
-#endif
- return ret;
-}
-
-/*
- * Notify the extension that the Crtc gamma has been changed
- * The driver calls this whenever it has changed the gamma values
- * in the RRCrtcRec
- */
-
-Bool
-RRCrtcGammaNotify (RRCrtcPtr crtc)
-{
- return TRUE; /* not much going on here */
-}
-
-static void
-RRModeGetScanoutSize (RRModePtr mode, PictTransformPtr transform,
- int *width, int *height)
-{
- BoxRec box;
-
- if (mode == NULL) {
- *width = 0;
- *height = 0;
- return;
- }
-
- box.x1 = 0;
- box.y1 = 0;
- box.x2 = mode->mode.width;
- box.y2 = mode->mode.height;
-
- pixman_transform_bounds (transform, &box);
- *width = box.x2 - box.x1;
- *height = box.y2 - box.y1;
-}
-
-/**
- * Returns the width/height that the crtc scans out from the framebuffer
- */
-void
-RRCrtcGetScanoutSize(RRCrtcPtr crtc, int *width, int *height)
-{
- return RRModeGetScanoutSize (crtc->mode, &crtc->transform, width, height);
-}
-
-/*
- * Set the size of the gamma table at server startup time
- */
-
-Bool
-RRCrtcGammaSetSize (RRCrtcPtr crtc,
- int size)
-{
- CARD16 *gamma;
-
- if (size == crtc->gammaSize)
- return TRUE;
- if (size)
- {
- gamma = malloc(size * 3 * sizeof (CARD16));
- if (!gamma)
- return FALSE;
- }
- else
- gamma = NULL;
- free(crtc->gammaRed);
- crtc->gammaRed = gamma;
- crtc->gammaGreen = gamma + size;
- crtc->gammaBlue = gamma + size*2;
- crtc->gammaSize = size;
- return TRUE;
-}
-
-/*
- * Set the pending CRTC transformation
- */
-
-int
-RRCrtcTransformSet (RRCrtcPtr crtc,
- PictTransformPtr transform,
- struct pixman_f_transform *f_transform,
- struct pixman_f_transform *f_inverse,
- char *filter_name,
- int filter_len,
- xFixed *params,
- int nparams)
-{
- PictFilterPtr filter = NULL;
- int width = 0, height = 0;
-
- if (!crtc->transforms)
- return BadValue;
-
- if (filter_len)
- {
- filter = PictureFindFilter (crtc->pScreen,
- filter_name,
- filter_len);
- if (!filter)
- return BadName;
- if (filter->ValidateParams)
- {
- if (!filter->ValidateParams (crtc->pScreen, filter->id,
- params, nparams, &width, &height))
- return BadMatch;
- }
- else {
- width = filter->width;
- height = filter->height;
- }
- }
- else
- {
- if (nparams)
- return BadMatch;
- }
- if (!RRTransformSetFilter (&crtc->client_pending_transform,
- filter, params, nparams, width, height))
- return BadAlloc;
-
- crtc->client_pending_transform.transform = *transform;
- crtc->client_pending_transform.f_transform = *f_transform;
- crtc->client_pending_transform.f_inverse = *f_inverse;
- return Success;
-}
-
-/*
- * Initialize crtc type
- */
-Bool
-RRCrtcInit (void)
-{
- RRCrtcType = CreateNewResourceType (RRCrtcDestroyResource, "CRTC");
- if (!RRCrtcType)
- return FALSE;
-
- return TRUE;
-}
-
-/*
- * Initialize crtc type error value
- */
-void
-RRCrtcInitErrorValue(void)
-{
- SetResourceTypeErrorValue(RRCrtcType, RRErrorBase + BadRRCrtc);
-}
-
-int
-ProcRRGetCrtcInfo (ClientPtr client)
-{
- REQUEST(xRRGetCrtcInfoReq);
- xRRGetCrtcInfoReply rep;
- RRCrtcPtr crtc;
- CARD8 *extra;
- unsigned long extraLen;
- ScreenPtr pScreen;
- rrScrPrivPtr pScrPriv;
- RRModePtr mode;
- RROutput *outputs;
- RROutput *possible;
- int i, j, k, n;
- int width, height;
- BoxRec panned_area;
-
- REQUEST_SIZE_MATCH(xRRGetCrtcInfoReq);
- VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
-
- /* All crtcs must be associated with screens before client
- * requests are processed
- */
- pScreen = crtc->pScreen;
- pScrPriv = rrGetScrPriv(pScreen);
-
- mode = crtc->mode;
-
- rep.type = X_Reply;
- rep.status = RRSetConfigSuccess;
- rep.sequenceNumber = client->sequence;
- rep.length = 0;
- rep.timestamp = pScrPriv->lastSetTime.milliseconds;
- if (pScrPriv->rrGetPanning &&
- pScrPriv->rrGetPanning (pScreen, crtc, &panned_area, NULL, NULL) &&
- (panned_area.x2 > panned_area.x1) && (panned_area.y2 > panned_area.y1))
- {
- rep.x = panned_area.x1;
- rep.y = panned_area.y1;
- rep.width = panned_area.x2 - panned_area.x1;
- rep.height = panned_area.y2 - panned_area.y1;
- }
- else
- {
- RRCrtcGetScanoutSize (crtc, &width, &height);
- rep.x = crtc->x;
- rep.y = crtc->y;
- rep.width = width;
- rep.height = height;
- }
- rep.mode = mode ? mode->mode.id : 0;
- rep.rotation = crtc->rotation;
- rep.rotations = crtc->rotations;
- rep.nOutput = crtc->numOutputs;
- k = 0;
- for (i = 0; i < pScrPriv->numOutputs; i++)
- for (j = 0; j < pScrPriv->outputs[i]->numCrtcs; j++)
- if (pScrPriv->outputs[i]->crtcs[j] == crtc)
- k++;
- rep.nPossibleOutput = k;
-
- rep.length = rep.nOutput + rep.nPossibleOutput;
-
- extraLen = rep.length << 2;
- if (extraLen)
- {
- extra = malloc(extraLen);
- if (!extra)
- return BadAlloc;
- }
- else
- extra = NULL;
-
- outputs = (RROutput *) extra;
- possible = (RROutput *) (outputs + rep.nOutput);
-
- for (i = 0; i < crtc->numOutputs; i++)
- {
- outputs[i] = crtc->outputs[i]->id;
- if (client->swapped)
- swapl (&outputs[i], n);
- }
- k = 0;
- for (i = 0; i < pScrPriv->numOutputs; i++)
- for (j = 0; j < pScrPriv->outputs[i]->numCrtcs; j++)
- if (pScrPriv->outputs[i]->crtcs[j] == crtc)
- {
- possible[k] = pScrPriv->outputs[i]->id;
- if (client->swapped)
- swapl (&possible[k], n);
- k++;
- }
-
- if (client->swapped) {
- swaps(&rep.sequenceNumber, n);
- swapl(&rep.length, n);
- swapl(&rep.timestamp, n);
- swaps(&rep.x, n);
- swaps(&rep.y, n);
- swaps(&rep.width, n);
- swaps(&rep.height, n);
- swapl(&rep.mode, n);
- swaps(&rep.rotation, n);
- swaps(&rep.rotations, n);
- swaps(&rep.nOutput, n);
- swaps(&rep.nPossibleOutput, n);
- }
- WriteToClient(client, sizeof(xRRGetCrtcInfoReply), (char *)&rep);
- if (extraLen)
- {
- WriteToClient (client, extraLen, (char *) extra);
- free(extra);
- }
-
- return Success;
-}
-
-int
-ProcRRSetCrtcConfig (ClientPtr client)
-{
- REQUEST(xRRSetCrtcConfigReq);
- xRRSetCrtcConfigReply rep;
- ScreenPtr pScreen;
- rrScrPrivPtr pScrPriv;
- RRCrtcPtr crtc;
- RRModePtr mode;
- int numOutputs;
- RROutputPtr *outputs = NULL;
- RROutput *outputIds;
- TimeStamp configTime;
- TimeStamp time;
- Rotation rotation;
- int rc, i, j;
-
- REQUEST_AT_LEAST_SIZE(xRRSetCrtcConfigReq);
- numOutputs = (stuff->length - bytes_to_int32(SIZEOF (xRRSetCrtcConfigReq)));
-
- VERIFY_RR_CRTC(stuff->crtc, crtc, DixSetAttrAccess);
-
- if (stuff->mode == None)
- {
- mode = NULL;
- if (numOutputs > 0)
- return BadMatch;
- }
- else
- {
- VERIFY_RR_MODE(stuff->mode, mode, DixSetAttrAccess);
- if (numOutputs == 0)
- return BadMatch;
- }
- if (numOutputs)
- {
- outputs = malloc(numOutputs * sizeof (RROutputPtr));
- if (!outputs)
- return BadAlloc;
- }
- else
- outputs = NULL;
-
- outputIds = (RROutput *) (stuff + 1);
- for (i = 0; i < numOutputs; i++)
- {
- rc = dixLookupResourceByType((pointer *)(outputs + i), outputIds[i],
- RROutputType, client, DixSetAttrAccess);
- if (rc != Success)
- {
- free(outputs);
- return rc;
- }
- /* validate crtc for this output */
- for (j = 0; j < outputs[i]->numCrtcs; j++)
- if (outputs[i]->crtcs[j] == crtc)
- break;
- if (j == outputs[i]->numCrtcs)
- {
- free(outputs);
- return BadMatch;
- }
- /* validate mode for this output */
- for (j = 0; j < outputs[i]->numModes + outputs[i]->numUserModes; j++)
- {
- RRModePtr m = (j < outputs[i]->numModes ?
- outputs[i]->modes[j] :
- outputs[i]->userModes[j - outputs[i]->numModes]);
- if (m == mode)
- break;
- }
- if (j == outputs[i]->numModes + outputs[i]->numUserModes)
- {
- free(outputs);
- return BadMatch;
- }
- }
- /* validate clones */
- for (i = 0; i < numOutputs; i++)
- {
- for (j = 0; j < numOutputs; j++)
- {
- int k;
- if (i == j)
- continue;
- for (k = 0; k < outputs[i]->numClones; k++)
- {
- if (outputs[i]->clones[k] == outputs[j])
- break;
- }
- if (k == outputs[i]->numClones)
- {
- free(outputs);
- return BadMatch;
- }
- }
- }
-
- pScreen = crtc->pScreen;
- pScrPriv = rrGetScrPriv(pScreen);
-
- time = ClientTimeToServerTime(stuff->timestamp);
- configTime = ClientTimeToServerTime(stuff->configTimestamp);
-
- if (!pScrPriv)
- {
- time = currentTime;
- rep.status = RRSetConfigFailed;
- goto sendReply;
- }
-
- /*
- * Validate requested rotation
- */
- rotation = (Rotation) stuff->rotation;
-
- /* test the rotation bits only! */
- switch (rotation & 0xf) {
- case RR_Rotate_0:
- case RR_Rotate_90:
- case RR_Rotate_180:
- case RR_Rotate_270:
- break;
- default:
- /*
- * Invalid rotation
- */
- client->errorValue = stuff->rotation;
- free(outputs);
- return BadValue;
- }
-
- if (mode)
- {
- if ((~crtc->rotations) & rotation)
- {
- /*
- * requested rotation or reflection not supported by screen
- */
- client->errorValue = stuff->rotation;
- free(outputs);
- return BadMatch;
- }
-
-#ifdef RANDR_12_INTERFACE
- /*
- * Check screen size bounds if the DDX provides a 1.2 interface
- * for setting screen size. Else, assume the CrtcSet sets
- * the size along with the mode. If the driver supports transforms,
- * then it must allow crtcs to display a subset of the screen, so
- * only do this check for drivers without transform support.
- */
- if (pScrPriv->rrScreenSetSize && !crtc->transforms)
- {
- int source_width;
- int source_height;
- PictTransform transform;
- struct pixman_f_transform f_transform, f_inverse;
-
- RRTransformCompute (stuff->x, stuff->y,
- mode->mode.width, mode->mode.height,
- rotation,
- &crtc->client_pending_transform,
- &transform, &f_transform, &f_inverse);
-
- RRModeGetScanoutSize (mode, &transform, &source_width, &source_height);
- if (stuff->x + source_width > pScreen->width)
- {
- client->errorValue = stuff->x;
- free(outputs);
- return BadValue;
- }
-
- if (stuff->y + source_height > pScreen->height)
- {
- client->errorValue = stuff->y;
- free(outputs);
- return BadValue;
- }
- }
-#endif
- }
-
- if (!RRCrtcSet (crtc, mode, stuff->x, stuff->y,
- rotation, numOutputs, outputs))
- {
- rep.status = RRSetConfigFailed;
- goto sendReply;
- }
- rep.status = RRSetConfigSuccess;
- pScrPriv->lastSetTime = time;
-
-sendReply:
- free(outputs);
-
- rep.type = X_Reply;
- /* rep.status has already been filled in */
- rep.length = 0;
- rep.sequenceNumber = client->sequence;
- rep.newTimestamp = pScrPriv->lastSetTime.milliseconds;
-
- if (client->swapped)
- {
- int n;
- swaps(&rep.sequenceNumber, n);
- swapl(&rep.length, n);
- swapl(&rep.newTimestamp, n);
- }
- WriteToClient(client, sizeof(xRRSetCrtcConfigReply), (char *)&rep);
-
- return Success;
-}
-
-int
-ProcRRGetPanning (ClientPtr client)
-{
- REQUEST(xRRGetPanningReq);
- xRRGetPanningReply rep;
- RRCrtcPtr crtc;
- ScreenPtr pScreen;
- rrScrPrivPtr pScrPriv;
- BoxRec total;
- BoxRec tracking;
- INT16 border[4];
- int n;
-
- REQUEST_SIZE_MATCH(xRRGetPanningReq);
- VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
-
- /* All crtcs must be associated with screens before client
- * requests are processed
- */
- pScreen = crtc->pScreen;
- pScrPriv = rrGetScrPriv(pScreen);
-
- if (!pScrPriv)
- return RRErrorBase + BadRRCrtc;
-
- memset(&rep, 0, sizeof(rep));
- rep.type = X_Reply;
- rep.status = RRSetConfigSuccess;
- rep.sequenceNumber = client->sequence;
- rep.length = 1;
- rep.timestamp = pScrPriv->lastSetTime.milliseconds;
-
- if (pScrPriv->rrGetPanning &&
- pScrPriv->rrGetPanning (pScreen, crtc, &total, &tracking, border)) {
- rep.left = total.x1;
- rep.top = total.y1;
- rep.width = total.x2 - total.x1;
- rep.height = total.y2 - total.y1;
- rep.track_left = tracking.x1;
- rep.track_top = tracking.y1;
- rep.track_width = tracking.x2 - tracking.x1;
- rep.track_height = tracking.y2 - tracking.y1;
- rep.border_left = border[0];
- rep.border_top = border[1];
- rep.border_right = border[2];
- rep.border_bottom = border[3];
- }
-
- if (client->swapped) {
- swaps(&rep.sequenceNumber, n);
- swapl(&rep.length, n);
- swaps(&rep.timestamp, n);
- swaps(&rep.left, n);
- swaps(&rep.top, n);
- swaps(&rep.width, n);
- swaps(&rep.height, n);
- swaps(&rep.track_left, n);
- swaps(&rep.track_top, n);
- swaps(&rep.track_width, n);
- swaps(&rep.track_height, n);
- swaps(&rep.border_left, n);
- swaps(&rep.border_top, n);
- swaps(&rep.border_right, n);
- swaps(&rep.border_bottom, n);
- }
- WriteToClient(client, sizeof(xRRGetPanningReply), (char *)&rep);
- return Success;
-}
-
-int
-ProcRRSetPanning (ClientPtr client)
-{
- REQUEST(xRRSetPanningReq);
- xRRSetPanningReply rep;
- RRCrtcPtr crtc;
- ScreenPtr pScreen;
- rrScrPrivPtr pScrPriv;
- TimeStamp time;
- BoxRec total;
- BoxRec tracking;
- INT16 border[4];
- int n;
-
- REQUEST_SIZE_MATCH(xRRSetPanningReq);
- VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
-
- /* All crtcs must be associated with screens before client
- * requests are processed
- */
- pScreen = crtc->pScreen;
- pScrPriv = rrGetScrPriv(pScreen);
-
- if (!pScrPriv) {
- time = currentTime;
- rep.status = RRSetConfigFailed;
- goto sendReply;
- }
-
- time = ClientTimeToServerTime(stuff->timestamp);
-
- if (!pScrPriv->rrGetPanning)
- return RRErrorBase + BadRRCrtc;
-
- total.x1 = stuff->left;
- total.y1 = stuff->top;
- total.x2 = total.x1 + stuff->width;
- total.y2 = total.y1 + stuff->height;
- tracking.x1 = stuff->track_left;
- tracking.y1 = stuff->track_top;
- tracking.x2 = tracking.x1 + stuff->track_width;
- tracking.y2 = tracking.y1 + stuff->track_height;
- border[0] = stuff->border_left;
- border[1] = stuff->border_top;
- border[2] = stuff->border_right;
- border[3] = stuff->border_bottom;
-
- if (! pScrPriv->rrSetPanning (pScreen, crtc, &total, &tracking, border))
- return BadMatch;
-
- pScrPriv->lastSetTime = time;
-
- rep.status = RRSetConfigSuccess;
-
-sendReply:
- rep.type = X_Reply;
- rep.sequenceNumber = client->sequence;
- rep.length = 0;
- rep.newTimestamp = pScrPriv->lastSetTime.milliseconds;
-
- if (client->swapped) {
- swaps(&rep.sequenceNumber, n);
- swapl(&rep.length, n);
- swaps(&rep.newTimestamp, n);
- }
- WriteToClient(client, sizeof(xRRSetPanningReply), (char *)&rep);
- return Success;
-}
-
-int
-ProcRRGetCrtcGammaSize (ClientPtr client)
-{
- REQUEST(xRRGetCrtcGammaSizeReq);
- xRRGetCrtcGammaSizeReply reply;
- RRCrtcPtr crtc;
- int n;
-
- REQUEST_SIZE_MATCH(xRRGetCrtcGammaSizeReq);
- VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
-
- /* Gamma retrieval failed, any better error? */
- if (!RRCrtcGammaGet(crtc))
- return RRErrorBase + BadRRCrtc;
-
- reply.type = X_Reply;
- reply.sequenceNumber = client->sequence;
- reply.length = 0;
- reply.size = crtc->gammaSize;
- if (client->swapped) {
- swaps (&reply.sequenceNumber, n);
- swapl (&reply.length, n);
- swaps (&reply.size, n);
- }
- WriteToClient (client, sizeof (xRRGetCrtcGammaSizeReply), (char *) &reply);
- return Success;
-}
-
-int
-ProcRRGetCrtcGamma (ClientPtr client)
-{
- REQUEST(xRRGetCrtcGammaReq);
- xRRGetCrtcGammaReply reply;
- RRCrtcPtr crtc;
- int n;
- unsigned long len;
- char *extra = NULL;
-
- REQUEST_SIZE_MATCH(xRRGetCrtcGammaReq);
- VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
-
- /* Gamma retrieval failed, any better error? */
- if (!RRCrtcGammaGet(crtc))
- return RRErrorBase + BadRRCrtc;
-
- len = crtc->gammaSize * 3 * 2;
-
- if (crtc->gammaSize) {
- extra = malloc(len);
- if (!extra)
- return BadAlloc;
- }
-
- reply.type = X_Reply;
- reply.sequenceNumber = client->sequence;
- reply.length = bytes_to_int32(len);
- reply.size = crtc->gammaSize;
- if (client->swapped) {
- swaps (&reply.sequenceNumber, n);
- swapl (&reply.length, n);
- swaps (&reply.size, n);
- }
- WriteToClient (client, sizeof (xRRGetCrtcGammaReply), (char *) &reply);
- if (crtc->gammaSize)
- {
- memcpy(extra, crtc->gammaRed, len);
- client->pSwapReplyFunc = (ReplySwapPtr)CopySwap16Write;
- WriteSwappedDataToClient (client, len, extra);
- free(extra);
- }
- return Success;
-}
-
-int
-ProcRRSetCrtcGamma (ClientPtr client)
-{
- REQUEST(xRRSetCrtcGammaReq);
- RRCrtcPtr crtc;
- unsigned long len;
- CARD16 *red, *green, *blue;
-
- REQUEST_AT_LEAST_SIZE(xRRSetCrtcGammaReq);
- VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
-
- len = client->req_len - bytes_to_int32(sizeof (xRRSetCrtcGammaReq));
- if (len < (stuff->size * 3 + 1) >> 1)
- return BadLength;
-
- if (stuff->size != crtc->gammaSize)
- return BadMatch;
-
- red = (CARD16 *) (stuff + 1);
- green = red + crtc->gammaSize;
- blue = green + crtc->gammaSize;
-
- RRCrtcGammaSet (crtc, red, green, blue);
-
- return Success;
-}
-
-/* Version 1.3 additions */
-
-int
-ProcRRSetCrtcTransform (ClientPtr client)
-{
- REQUEST(xRRSetCrtcTransformReq);
- RRCrtcPtr crtc;
- PictTransform transform;
- struct pixman_f_transform f_transform, f_inverse;
- char *filter;
- int nbytes;
- xFixed *params;
- int nparams;
-
- REQUEST_AT_LEAST_SIZE(xRRSetCrtcTransformReq);
- VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
-
- PictTransform_from_xRenderTransform (&transform, &stuff->transform);
- pixman_f_transform_from_pixman_transform (&f_transform, &transform);
- if (!pixman_f_transform_invert (&f_inverse, &f_transform))
- return BadMatch;
-
- filter = (char *) (stuff + 1);
- nbytes = stuff->nbytesFilter;
- params = (xFixed *) (filter + pad_to_int32(nbytes));
- nparams = ((xFixed *) stuff + client->req_len) - params;
- if (nparams < 0)
- return BadLength;
-
- return RRCrtcTransformSet (crtc, &transform, &f_transform, &f_inverse,
- filter, nbytes, params, nparams);
-}
-
-
-#define CrtcTransformExtra (SIZEOF(xRRGetCrtcTransformReply) - 32)
-
-static int
-transform_filter_length (RRTransformPtr transform)
-{
- int nbytes, nparams;
-
- if (transform->filter == NULL)
- return 0;
- nbytes = strlen (transform->filter->name);
- nparams = transform->nparams;
- return pad_to_int32(nbytes) + (nparams * sizeof (xFixed));
-}
-
-static int
-transform_filter_encode (ClientPtr client, char *output,
- CARD16 *nbytesFilter,
- CARD16 *nparamsFilter,
- RRTransformPtr transform)
-{
- int nbytes, nparams;
- int n;
-
- if (transform->filter == NULL) {
- *nbytesFilter = 0;
- *nparamsFilter = 0;
- return 0;
- }
- nbytes = strlen (transform->filter->name);
- nparams = transform->nparams;
- *nbytesFilter = nbytes;
- *nparamsFilter = nparams;
- memcpy (output, transform->filter->name, nbytes);
- while ((nbytes & 3) != 0)
- output[nbytes++] = 0;
- memcpy (output + nbytes, transform->params, nparams * sizeof (xFixed));
- if (client->swapped) {
- swaps (nbytesFilter, n);
- swaps (nparamsFilter, n);
- SwapLongs ((CARD32 *) (output + nbytes), nparams);
- }
- nbytes += nparams * sizeof (xFixed);
- return nbytes;
-}
-
-static void
-transform_encode (ClientPtr client, xRenderTransform *wire, PictTransform *pict)
-{
- xRenderTransform_from_PictTransform (wire, pict);
- if (client->swapped)
- SwapLongs ((CARD32 *) wire, bytes_to_int32(sizeof(xRenderTransform)));
-}
-
-int
-ProcRRGetCrtcTransform (ClientPtr client)
-{
- REQUEST(xRRGetCrtcTransformReq);
- xRRGetCrtcTransformReply *reply;
- RRCrtcPtr crtc;
- int n, nextra;
- RRTransformPtr current, pending;
- char *extra;
-
- REQUEST_SIZE_MATCH (xRRGetCrtcTransformReq);
- VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
-
- pending = &crtc->client_pending_transform;
- current = &crtc->client_current_transform;
-
- nextra = (transform_filter_length (pending) +
- transform_filter_length (current));
-
- reply = malloc(sizeof (xRRGetCrtcTransformReply) + nextra);
- if (!reply)
- return BadAlloc;
-
- extra = (char *) (reply + 1);
- reply->type = X_Reply;
- reply->sequenceNumber = client->sequence;
- reply->length = bytes_to_int32(CrtcTransformExtra + nextra);
-
- reply->hasTransforms = crtc->transforms;
-
- transform_encode (client, &reply->pendingTransform, &pending->transform);
- extra += transform_filter_encode (client, extra,
- &reply->pendingNbytesFilter,
- &reply->pendingNparamsFilter,
- pending);
-
- transform_encode (client, &reply->currentTransform, &current->transform);
- extra += transform_filter_encode (client, extra,
- &reply->currentNbytesFilter,
- &reply->currentNparamsFilter,
- current);
-
- if (client->swapped) {
- swaps (&reply->sequenceNumber, n);
- swapl (&reply->length, n);
- }
- WriteToClient (client, sizeof (xRRGetCrtcTransformReply) + nextra, (char *) reply);
- free(reply);
- return Success;
-}
-
-void
-RRConstrainCursorHarder(DeviceIntPtr pDev, ScreenPtr pScreen, int mode, int *x, int *y)
-{
- rrScrPriv (pScreen);
- int i;
-
- /* intentional dead space -> let it float */
- if (pScrPriv->discontiguous)
- return;
-
- /* if we're moving inside a crtc, we're fine */
- for (i = 0; i < pScrPriv->numCrtcs; i++) {
- RRCrtcPtr crtc = pScrPriv->crtcs[i];
-
- int left, right, top, bottom;
-
- if (!crtc->mode)
- continue;
-
- crtc_bounds(crtc, &left, &right, &top, &bottom);
-
- if ((*x >= left) && (*x <= right) && (*y >= top) && (*y <= bottom))
- return;
- }
-
- /* if we're trying to escape, clamp to the CRTC we're coming from */
- for (i = 0; i < pScrPriv->numCrtcs; i++) {
- RRCrtcPtr crtc = pScrPriv->crtcs[i];
- int nx, ny;
- int left, right, top, bottom;
-
- if (!crtc->mode)
- continue;
-
- crtc_bounds(crtc, &left, &right, &top, &bottom);
- miPointerGetPosition(pDev, &nx, &ny);
-
- if ((nx >= left) && (nx <= right) && (ny >= top) && (ny <= bottom)) {
- if ((*x <= left) || (*x >= right)) {
- int dx = *x - nx;
-
- if (dx > 0)
- *x = right;
- else if (dx < 0)
- *x = left;
- }
-
- if ((*y <= top) || (*y >= bottom)) {
- int dy = *y - ny;
-
- if (dy > 0)
- *y = bottom;
- else if (dy < 0)
- *y = top;
- }
-
- return;
- }
- }
-}
+/*
+ * Copyright © 2006 Keith Packard
+ * Copyright 2010 Red Hat, 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.
+ */
+
+#include "randrstr.h"
+#include "swaprep.h"
+#include "mipointer.h"
+
+RESTYPE RRCrtcType;
+
+/*
+ * Notify the CRTC of some change
+ */
+void
+RRCrtcChanged (RRCrtcPtr crtc, Bool layoutChanged)
+{
+ ScreenPtr pScreen = crtc->pScreen;
+
+ crtc->changed = TRUE;
+ if (pScreen)
+ {
+ rrScrPriv(pScreen);
+
+ pScrPriv->changed = TRUE;
+ /*
+ * Send ConfigureNotify on any layout change
+ */
+ if (layoutChanged)
+ pScrPriv->layoutChanged = TRUE;
+ }
+}
+
+/*
+ * Create a CRTC
+ */
+RRCrtcPtr
+RRCrtcCreate (ScreenPtr pScreen, void *devPrivate)
+{
+ RRCrtcPtr crtc;
+ RRCrtcPtr *crtcs;
+ rrScrPrivPtr pScrPriv;
+
+ if (!RRInit())
+ return NULL;
+
+ pScrPriv = rrGetScrPriv(pScreen);
+
+ /* make space for the crtc pointer */
+ if (pScrPriv->numCrtcs)
+ crtcs = realloc(pScrPriv->crtcs,
+ (pScrPriv->numCrtcs + 1) * sizeof (RRCrtcPtr));
+ else
+ crtcs = malloc(sizeof (RRCrtcPtr));
+ if (!crtcs)
+ return FALSE;
+ pScrPriv->crtcs = crtcs;
+
+ crtc = calloc(1, sizeof (RRCrtcRec));
+ if (!crtc)
+ return NULL;
+ crtc->id = FakeClientID (0);
+ crtc->pScreen = pScreen;
+ crtc->mode = NULL;
+ crtc->x = 0;
+ crtc->y = 0;
+ crtc->rotation = RR_Rotate_0;
+ crtc->rotations = RR_Rotate_0;
+ crtc->outputs = NULL;
+ crtc->numOutputs = 0;
+ crtc->gammaSize = 0;
+ crtc->gammaRed = crtc->gammaBlue = crtc->gammaGreen = NULL;
+ crtc->changed = FALSE;
+ crtc->devPrivate = devPrivate;
+ RRTransformInit (&crtc->client_pending_transform);
+ RRTransformInit (&crtc->client_current_transform);
+ pixman_transform_init_identity (&crtc->transform);
+ pixman_f_transform_init_identity (&crtc->f_transform);
+ pixman_f_transform_init_identity (&crtc->f_inverse);
+
+ if (!AddResource (crtc->id, RRCrtcType, (pointer) crtc))
+ return NULL;
+
+ /* attach the screen and crtc together */
+ crtc->pScreen = pScreen;
+ pScrPriv->crtcs[pScrPriv->numCrtcs++] = crtc;
+
+ return crtc;
+}
+
+/*
+ * Set the allowed rotations on a CRTC
+ */
+void
+RRCrtcSetRotations (RRCrtcPtr crtc, Rotation rotations)
+{
+ crtc->rotations = rotations;
+}
+
+/*
+ * Set whether transforms are allowed on a CRTC
+ */
+void
+RRCrtcSetTransformSupport (RRCrtcPtr crtc, Bool transforms)
+{
+ crtc->transforms = transforms;
+}
+
+/*
+ * Notify the extension that the Crtc has been reconfigured,
+ * the driver calls this whenever it has updated the mode
+ */
+Bool
+RRCrtcNotify (RRCrtcPtr crtc,
+ RRModePtr mode,
+ int x,
+ int y,
+ Rotation rotation,
+ RRTransformPtr transform,
+ int numOutputs,
+ RROutputPtr *outputs)
+{
+ int i, j;
+
+ /*
+ * Check to see if any of the new outputs were
+ * not in the old list and mark them as changed
+ */
+ for (i = 0; i < numOutputs; i++)
+ {
+ for (j = 0; j < crtc->numOutputs; j++)
+ if (outputs[i] == crtc->outputs[j])
+ break;
+ if (j == crtc->numOutputs)
+ {
+ outputs[i]->crtc = crtc;
+ RROutputChanged (outputs[i], FALSE);
+ RRCrtcChanged (crtc, FALSE);
+ }
+ }
+ /*
+ * Check to see if any of the old outputs are
+ * not in the new list and mark them as changed
+ */
+ for (j = 0; j < crtc->numOutputs; j++)
+ {
+ for (i = 0; i < numOutputs; i++)
+ if (outputs[i] == crtc->outputs[j])
+ break;
+ if (i == numOutputs)
+ {
+ if (crtc->outputs[j]->crtc == crtc)
+ crtc->outputs[j]->crtc = NULL;
+ RROutputChanged (crtc->outputs[j], FALSE);
+ RRCrtcChanged (crtc, FALSE);
+ }
+ }
+ /*
+ * Reallocate the crtc output array if necessary
+ */
+ if (numOutputs != crtc->numOutputs)
+ {
+ RROutputPtr *newoutputs;
+
+ if (numOutputs)
+ {
+ if (crtc->numOutputs)
+ newoutputs = realloc(crtc->outputs,
+ numOutputs * sizeof (RROutputPtr));
+ else
+ newoutputs = malloc(numOutputs * sizeof (RROutputPtr));
+ if (!newoutputs)
+ return FALSE;
+ }
+ else
+ {
+ free(crtc->outputs);
+ newoutputs = NULL;
+ }
+ crtc->outputs = newoutputs;
+ crtc->numOutputs = numOutputs;
+ }
+ /*
+ * Copy the new list of outputs into the crtc
+ */
+ memcpy (crtc->outputs, outputs, numOutputs * sizeof (RROutputPtr));
+ /*
+ * Update remaining crtc fields
+ */
+ if (mode != crtc->mode)
+ {
+ if (crtc->mode)
+ RRModeDestroy (crtc->mode);
+ crtc->mode = mode;
+ if (mode != NULL)
+ mode->refcnt++;
+ RRCrtcChanged (crtc, TRUE);
+ }
+ if (x != crtc->x)
+ {
+ crtc->x = x;
+ RRCrtcChanged (crtc, TRUE);
+ }
+ if (y != crtc->y)
+ {
+ crtc->y = y;
+ RRCrtcChanged (crtc, TRUE);
+ }
+ if (rotation != crtc->rotation)
+ {
+ crtc->rotation = rotation;
+ RRCrtcChanged (crtc, TRUE);
+ }
+ if (!RRTransformEqual (transform, &crtc->client_current_transform)) {
+ RRTransformCopy (&crtc->client_current_transform, transform);
+ RRCrtcChanged (crtc, TRUE);
+ }
+ if (crtc->changed && mode)
+ {
+ RRTransformCompute (x, y,
+ mode->mode.width, mode->mode.height,
+ rotation,
+ &crtc->client_current_transform,
+ &crtc->transform, &crtc->f_transform,
+ &crtc->f_inverse);
+ }
+ return TRUE;
+}
+
+void
+RRDeliverCrtcEvent (ClientPtr client, WindowPtr pWin, RRCrtcPtr crtc)
+{
+ ScreenPtr pScreen = pWin->drawable.pScreen;
+ rrScrPriv (pScreen);
+ xRRCrtcChangeNotifyEvent ce;
+ RRModePtr mode = crtc->mode;
+
+ ce.type = RRNotify + RREventBase;
+ ce.subCode = RRNotify_CrtcChange;
+ ce.timestamp = pScrPriv->lastSetTime.milliseconds;
+ ce.window = pWin->drawable.id;
+ ce.crtc = crtc->id;
+ ce.rotation = crtc->rotation;
+ if (mode)
+ {
+ ce.mode = mode->mode.id;
+ ce.x = crtc->x;
+ ce.y = crtc->y;
+ ce.width = mode->mode.width;
+ ce.height = mode->mode.height;
+ }
+ else
+ {
+ ce.mode = None;
+ ce.x = 0;
+ ce.y = 0;
+ ce.width = 0;
+ ce.height = 0;
+ }
+ WriteEventsToClient (client, 1, (xEvent *) &ce);
+}
+
+static Bool
+RRCrtcPendingProperties (RRCrtcPtr crtc)
+{
+ ScreenPtr pScreen = crtc->pScreen;
+ rrScrPriv(pScreen);
+ int o;
+
+ for (o = 0; o < pScrPriv->numOutputs; o++)
+ {
+ RROutputPtr output = pScrPriv->outputs[o];
+ if (output->crtc == crtc && output->pendingProperties)
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static void
+crtc_bounds(RRCrtcPtr crtc, int *left, int *right, int *top, int *bottom)
+{
+ *left = crtc->x;
+ *top = crtc->y;
+
+ switch (crtc->rotation) {
+ case RR_Rotate_0:
+ case RR_Rotate_180:
+ default:
+ *right = crtc->x + crtc->mode->mode.width;
+ *bottom = crtc->y + crtc->mode->mode.height;
+ return;
+ case RR_Rotate_90:
+ case RR_Rotate_270:
+ *right = crtc->x + crtc->mode->mode.height;
+ *bottom = crtc->y + crtc->mode->mode.width;
+ return;
+ }
+}
+
+/* overlapping counts as adjacent */
+static Bool
+crtcs_adjacent(const RRCrtcPtr a, const RRCrtcPtr b)
+{
+ /* left, right, top, bottom... */
+ int al, ar, at, ab;
+ int bl, br, bt, bb;
+ int cl, cr, ct, cb; /* the overlap, if any */
+
+ crtc_bounds(a, &al, &ar, &at, &ab);
+ crtc_bounds(b, &bl, &br, &bt, &bb);
+
+ cl = max(al, bl);
+ cr = min(ar, br);
+ ct = max(at, bt);
+ cb = min(ab, bb);
+
+ return (cl <= cr) && (ct <= cb);
+}
+
+/* Depth-first search and mark all CRTCs reachable from cur */
+static void
+mark_crtcs (rrScrPrivPtr pScrPriv, int *reachable, int cur)
+{
+ int i;
+ reachable[cur] = TRUE;
+ for (i = 0; i < pScrPriv->numCrtcs; ++i) {
+ if (reachable[i] || !pScrPriv->crtcs[i]->mode)
+ continue;
+ if (crtcs_adjacent(pScrPriv->crtcs[cur], pScrPriv->crtcs[i]))
+ mark_crtcs(pScrPriv, reachable, i);
+ }
+}
+
+static void
+RRComputeContiguity (ScreenPtr pScreen)
+{
+ rrScrPriv(pScreen);
+ Bool discontiguous = TRUE;
+ int i, n = pScrPriv->numCrtcs;
+
+ int *reachable = calloc(n, sizeof(int));
+ if (!reachable)
+ goto out;
+
+ /* Find first enabled CRTC and start search for reachable CRTCs from it */
+ for (i = 0; i < n; ++i) {
+ if (pScrPriv->crtcs[i]->mode) {
+ mark_crtcs(pScrPriv, reachable, i);
+ break;
+ }
+ }
+
+ /* Check that all enabled CRTCs were marked as reachable */
+ for (i = 0; i < n; ++i)
+ if (pScrPriv->crtcs[i]->mode && !reachable[i])
+ goto out;
+
+ discontiguous = FALSE;
+
+out:
+ free(reachable);
+ pScrPriv->discontiguous = discontiguous;
+}
+
+/*
+ * Request that the Crtc be reconfigured
+ */
+Bool
+RRCrtcSet (RRCrtcPtr crtc,
+ RRModePtr mode,
+ int x,
+ int y,
+ Rotation rotation,
+ int numOutputs,
+ RROutputPtr *outputs)
+{
+ ScreenPtr pScreen = crtc->pScreen;
+ Bool ret = FALSE;
+ Bool recompute = TRUE;
+ rrScrPriv(pScreen);
+
+ /* See if nothing changed */
+ if (crtc->mode == mode &&
+ crtc->x == x &&
+ crtc->y == y &&
+ crtc->rotation == rotation &&
+ crtc->numOutputs == numOutputs &&
+ !memcmp (crtc->outputs, outputs, numOutputs * sizeof (RROutputPtr)) &&
+ !RRCrtcPendingProperties (crtc) &&
+ !RRCrtcPendingTransform (crtc))
+ {
+ recompute = FALSE;
+ ret = TRUE;
+ }
+ else
+ {
+#if RANDR_12_INTERFACE
+ if (pScrPriv->rrCrtcSet)
+ {
+ ret = (*pScrPriv->rrCrtcSet) (pScreen, crtc, mode, x, y,
+ rotation, numOutputs, outputs);
+ }
+ else
+#endif
+ {
+#if RANDR_10_INTERFACE
+ if (pScrPriv->rrSetConfig)
+ {
+ RRScreenSize size;
+ RRScreenRate rate;
+
+ if (!mode)
+ {
+ RRCrtcNotify (crtc, NULL, x, y, rotation, NULL, 0, NULL);
+ ret = TRUE;
+ }
+ else
+ {
+ size.width = mode->mode.width;
+ size.height = mode->mode.height;
+ if (outputs[0]->mmWidth && outputs[0]->mmHeight)
+ {
+ size.mmWidth = outputs[0]->mmWidth;
+ size.mmHeight = outputs[0]->mmHeight;
+ }
+ else
+ {
+ size.mmWidth = pScreen->mmWidth;
+ size.mmHeight = pScreen->mmHeight;
+ }
+ size.nRates = 1;
+ rate.rate = RRVerticalRefresh (&mode->mode);
+ size.pRates = &rate;
+ ret = (*pScrPriv->rrSetConfig) (pScreen, rotation, rate.rate, &size);
+ /*
+ * Old 1.0 interface tied screen size to mode size
+ */
+ if (ret)
+ {
+ RRCrtcNotify (crtc, mode, x, y, rotation, NULL, 1, outputs);
+ RRScreenSizeNotify (pScreen);
+ }
+ }
+ }
+#endif
+ }
+ if (ret)
+ {
+ int o;
+ RRTellChanged (pScreen);
+
+ for (o = 0; o < numOutputs; o++)
+ RRPostPendingProperties (outputs[o]);
+ }
+ }
+
+ if (recompute)
+ RRComputeContiguity(pScreen);
+
+ return ret;
+}
+
+/*
+ * Return crtc transform
+ */
+RRTransformPtr
+RRCrtcGetTransform (RRCrtcPtr crtc)
+{
+ RRTransformPtr transform = &crtc->client_pending_transform;
+
+ if (pixman_transform_is_identity (&transform->transform))
+ return NULL;
+ return transform;
+}
+
+/*
+ * Check whether the pending and current transforms are the same
+ */
+Bool
+RRCrtcPendingTransform (RRCrtcPtr crtc)
+{
+ return memcmp (&crtc->client_current_transform.transform,
+ &crtc->client_pending_transform.transform,
+ sizeof (PictTransform)) != 0;
+}
+
+/*
+ * Destroy a Crtc at shutdown
+ */
+void
+RRCrtcDestroy (RRCrtcPtr crtc)
+{
+ FreeResource (crtc->id, 0);
+}
+
+static int
+RRCrtcDestroyResource (pointer value, XID pid)
+{
+ RRCrtcPtr crtc = (RRCrtcPtr) value;
+ ScreenPtr pScreen = crtc->pScreen;
+
+ if (pScreen)
+ {
+ rrScrPriv(pScreen);
+ int i;
+
+ for (i = 0; i < pScrPriv->numCrtcs; i++)
+ {
+ if (pScrPriv->crtcs[i] == crtc)
+ {
+ memmove (pScrPriv->crtcs + i, pScrPriv->crtcs + i + 1,
+ (pScrPriv->numCrtcs - (i + 1)) * sizeof (RRCrtcPtr));
+ --pScrPriv->numCrtcs;
+ break;
+ }
+ }
+ }
+ free(crtc->gammaRed);
+ if (crtc->mode)
+ RRModeDestroy (crtc->mode);
+ free(crtc);
+ return 1;
+}
+
+/*
+ * Request that the Crtc gamma be changed
+ */
+
+Bool
+RRCrtcGammaSet (RRCrtcPtr crtc,
+ CARD16 *red,
+ CARD16 *green,
+ CARD16 *blue)
+{
+ Bool ret = TRUE;
+#if RANDR_12_INTERFACE
+ ScreenPtr pScreen = crtc->pScreen;
+#endif
+
+ memcpy (crtc->gammaRed, red, crtc->gammaSize * sizeof (CARD16));
+ memcpy (crtc->gammaGreen, green, crtc->gammaSize * sizeof (CARD16));
+ memcpy (crtc->gammaBlue, blue, crtc->gammaSize * sizeof (CARD16));
+#if RANDR_12_INTERFACE
+ if (pScreen)
+ {
+ rrScrPriv(pScreen);
+ if (pScrPriv->rrCrtcSetGamma)
+ ret = (*pScrPriv->rrCrtcSetGamma) (pScreen, crtc);
+ }
+#endif
+ return ret;
+}
+
+/*
+ * Request current gamma back from the DDX (if possible).
+ * This includes gamma size.
+ */
+Bool
+RRCrtcGammaGet(RRCrtcPtr crtc)
+{
+ Bool ret = TRUE;
+#if RANDR_12_INTERFACE
+ ScreenPtr pScreen = crtc->pScreen;
+#endif
+
+#if RANDR_12_INTERFACE
+ if (pScreen)
+ {
+ rrScrPriv(pScreen);
+ if (pScrPriv->rrCrtcGetGamma)
+ ret = (*pScrPriv->rrCrtcGetGamma) (pScreen, crtc);
+ }
+#endif
+ return ret;
+}
+
+/*
+ * Notify the extension that the Crtc gamma has been changed
+ * The driver calls this whenever it has changed the gamma values
+ * in the RRCrtcRec
+ */
+
+Bool
+RRCrtcGammaNotify (RRCrtcPtr crtc)
+{
+ return TRUE; /* not much going on here */
+}
+
+static void
+RRModeGetScanoutSize (RRModePtr mode, PictTransformPtr transform,
+ int *width, int *height)
+{
+ BoxRec box;
+
+ if (mode == NULL) {
+ *width = 0;
+ *height = 0;
+ return;
+ }
+
+ box.x1 = 0;
+ box.y1 = 0;
+ box.x2 = mode->mode.width;
+ box.y2 = mode->mode.height;
+
+ pixman_transform_bounds (transform, &box);
+ *width = box.x2 - box.x1;
+ *height = box.y2 - box.y1;
+}
+
+/**
+ * Returns the width/height that the crtc scans out from the framebuffer
+ */
+void
+RRCrtcGetScanoutSize(RRCrtcPtr crtc, int *width, int *height)
+{
+ RRModeGetScanoutSize (crtc->mode, &crtc->transform, width, height);
+}
+
+/*
+ * Set the size of the gamma table at server startup time
+ */
+
+Bool
+RRCrtcGammaSetSize (RRCrtcPtr crtc,
+ int size)
+{
+ CARD16 *gamma;
+
+ if (size == crtc->gammaSize)
+ return TRUE;
+ if (size)
+ {
+ gamma = malloc(size * 3 * sizeof (CARD16));
+ if (!gamma)
+ return FALSE;
+ }
+ else
+ gamma = NULL;
+ free(crtc->gammaRed);
+ crtc->gammaRed = gamma;
+ crtc->gammaGreen = gamma + size;
+ crtc->gammaBlue = gamma + size*2;
+ crtc->gammaSize = size;
+ return TRUE;
+}
+
+/*
+ * Set the pending CRTC transformation
+ */
+
+int
+RRCrtcTransformSet (RRCrtcPtr crtc,
+ PictTransformPtr transform,
+ struct pixman_f_transform *f_transform,
+ struct pixman_f_transform *f_inverse,
+ char *filter_name,
+ int filter_len,
+ xFixed *params,
+ int nparams)
+{
+ PictFilterPtr filter = NULL;
+ int width = 0, height = 0;
+
+ if (!crtc->transforms)
+ return BadValue;
+
+ if (filter_len)
+ {
+ filter = PictureFindFilter (crtc->pScreen,
+ filter_name,
+ filter_len);
+ if (!filter)
+ return BadName;
+ if (filter->ValidateParams)
+ {
+ if (!filter->ValidateParams (crtc->pScreen, filter->id,
+ params, nparams, &width, &height))
+ return BadMatch;
+ }
+ else {
+ width = filter->width;
+ height = filter->height;
+ }
+ }
+ else
+ {
+ if (nparams)
+ return BadMatch;
+ }
+ if (!RRTransformSetFilter (&crtc->client_pending_transform,
+ filter, params, nparams, width, height))
+ return BadAlloc;
+
+ crtc->client_pending_transform.transform = *transform;
+ crtc->client_pending_transform.f_transform = *f_transform;
+ crtc->client_pending_transform.f_inverse = *f_inverse;
+ return Success;
+}
+
+/*
+ * Initialize crtc type
+ */
+Bool
+RRCrtcInit (void)
+{
+ RRCrtcType = CreateNewResourceType (RRCrtcDestroyResource, "CRTC");
+ if (!RRCrtcType)
+ return FALSE;
+
+ return TRUE;
+}
+
+/*
+ * Initialize crtc type error value
+ */
+void
+RRCrtcInitErrorValue(void)
+{
+ SetResourceTypeErrorValue(RRCrtcType, RRErrorBase + BadRRCrtc);
+}
+
+int
+ProcRRGetCrtcInfo (ClientPtr client)
+{
+ REQUEST(xRRGetCrtcInfoReq);
+ xRRGetCrtcInfoReply rep;
+ RRCrtcPtr crtc;
+ CARD8 *extra;
+ unsigned long extraLen;
+ ScreenPtr pScreen;
+ rrScrPrivPtr pScrPriv;
+ RRModePtr mode;
+ RROutput *outputs;
+ RROutput *possible;
+ int i, j, k, n;
+ int width, height;
+ BoxRec panned_area;
+
+ REQUEST_SIZE_MATCH(xRRGetCrtcInfoReq);
+ VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
+
+ /* All crtcs must be associated with screens before client
+ * requests are processed
+ */
+ pScreen = crtc->pScreen;
+ pScrPriv = rrGetScrPriv(pScreen);
+
+ mode = crtc->mode;
+
+ rep.type = X_Reply;
+ rep.status = RRSetConfigSuccess;
+ rep.sequenceNumber = client->sequence;
+ rep.length = 0;
+ rep.timestamp = pScrPriv->lastSetTime.milliseconds;
+ if (pScrPriv->rrGetPanning &&
+ pScrPriv->rrGetPanning (pScreen, crtc, &panned_area, NULL, NULL) &&
+ (panned_area.x2 > panned_area.x1) && (panned_area.y2 > panned_area.y1))
+ {
+ rep.x = panned_area.x1;
+ rep.y = panned_area.y1;
+ rep.width = panned_area.x2 - panned_area.x1;
+ rep.height = panned_area.y2 - panned_area.y1;
+ }
+ else
+ {
+ RRCrtcGetScanoutSize (crtc, &width, &height);
+ rep.x = crtc->x;
+ rep.y = crtc->y;
+ rep.width = width;
+ rep.height = height;
+ }
+ rep.mode = mode ? mode->mode.id : 0;
+ rep.rotation = crtc->rotation;
+ rep.rotations = crtc->rotations;
+ rep.nOutput = crtc->numOutputs;
+ k = 0;
+ for (i = 0; i < pScrPriv->numOutputs; i++)
+ for (j = 0; j < pScrPriv->outputs[i]->numCrtcs; j++)
+ if (pScrPriv->outputs[i]->crtcs[j] == crtc)
+ k++;
+ rep.nPossibleOutput = k;
+
+ rep.length = rep.nOutput + rep.nPossibleOutput;
+
+ extraLen = rep.length << 2;
+ if (extraLen)
+ {
+ extra = malloc(extraLen);
+ if (!extra)
+ return BadAlloc;
+ }
+ else
+ extra = NULL;
+
+ outputs = (RROutput *) extra;
+ possible = (RROutput *) (outputs + rep.nOutput);
+
+ for (i = 0; i < crtc->numOutputs; i++)
+ {
+ outputs[i] = crtc->outputs[i]->id;
+ if (client->swapped)
+ swapl (&outputs[i], n);
+ }
+ k = 0;
+ for (i = 0; i < pScrPriv->numOutputs; i++)
+ for (j = 0; j < pScrPriv->outputs[i]->numCrtcs; j++)
+ if (pScrPriv->outputs[i]->crtcs[j] == crtc)
+ {
+ possible[k] = pScrPriv->outputs[i]->id;
+ if (client->swapped)
+ swapl (&possible[k], n);
+ k++;
+ }
+
+ if (client->swapped) {
+ swaps(&rep.sequenceNumber, n);
+ swapl(&rep.length, n);
+ swapl(&rep.timestamp, n);
+ swaps(&rep.x, n);
+ swaps(&rep.y, n);
+ swaps(&rep.width, n);
+ swaps(&rep.height, n);
+ swapl(&rep.mode, n);
+ swaps(&rep.rotation, n);
+ swaps(&rep.rotations, n);
+ swaps(&rep.nOutput, n);
+ swaps(&rep.nPossibleOutput, n);
+ }
+ WriteToClient(client, sizeof(xRRGetCrtcInfoReply), (char *)&rep);
+ if (extraLen)
+ {
+ WriteToClient (client, extraLen, (char *) extra);
+ free(extra);
+ }
+
+ return Success;
+}
+
+int
+ProcRRSetCrtcConfig (ClientPtr client)
+{
+ REQUEST(xRRSetCrtcConfigReq);
+ xRRSetCrtcConfigReply rep;
+ ScreenPtr pScreen;
+ rrScrPrivPtr pScrPriv;
+ RRCrtcPtr crtc;
+ RRModePtr mode;
+ int numOutputs;
+ RROutputPtr *outputs = NULL;
+ RROutput *outputIds;
+ TimeStamp configTime;
+ TimeStamp time;
+ Rotation rotation;
+ int rc, i, j;
+
+ REQUEST_AT_LEAST_SIZE(xRRSetCrtcConfigReq);
+ numOutputs = (stuff->length - bytes_to_int32(SIZEOF (xRRSetCrtcConfigReq)));
+
+ VERIFY_RR_CRTC(stuff->crtc, crtc, DixSetAttrAccess);
+
+ if (stuff->mode == None)
+ {
+ mode = NULL;
+ if (numOutputs > 0)
+ return BadMatch;
+ }
+ else
+ {
+ VERIFY_RR_MODE(stuff->mode, mode, DixSetAttrAccess);
+ if (numOutputs == 0)
+ return BadMatch;
+ }
+ if (numOutputs)
+ {
+ outputs = malloc(numOutputs * sizeof (RROutputPtr));
+ if (!outputs)
+ return BadAlloc;
+ }
+ else
+ outputs = NULL;
+
+ outputIds = (RROutput *) (stuff + 1);
+ for (i = 0; i < numOutputs; i++)
+ {
+ rc = dixLookupResourceByType((pointer *)(outputs + i), outputIds[i],
+ RROutputType, client, DixSetAttrAccess);
+ if (rc != Success)
+ {
+ free(outputs);
+ return rc;
+ }
+ /* validate crtc for this output */
+ for (j = 0; j < outputs[i]->numCrtcs; j++)
+ if (outputs[i]->crtcs[j] == crtc)
+ break;
+ if (j == outputs[i]->numCrtcs)
+ {
+ free(outputs);
+ return BadMatch;
+ }
+ /* validate mode for this output */
+ for (j = 0; j < outputs[i]->numModes + outputs[i]->numUserModes; j++)
+ {
+ RRModePtr m = (j < outputs[i]->numModes ?
+ outputs[i]->modes[j] :
+ outputs[i]->userModes[j - outputs[i]->numModes]);
+ if (m == mode)
+ break;
+ }
+ if (j == outputs[i]->numModes + outputs[i]->numUserModes)
+ {
+ free(outputs);
+ return BadMatch;
+ }
+ }
+ /* validate clones */
+ for (i = 0; i < numOutputs; i++)
+ {
+ for (j = 0; j < numOutputs; j++)
+ {
+ int k;
+ if (i == j)
+ continue;
+ for (k = 0; k < outputs[i]->numClones; k++)
+ {
+ if (outputs[i]->clones[k] == outputs[j])
+ break;
+ }
+ if (k == outputs[i]->numClones)
+ {
+ free(outputs);
+ return BadMatch;
+ }
+ }
+ }
+
+ pScreen = crtc->pScreen;
+ pScrPriv = rrGetScrPriv(pScreen);
+
+ time = ClientTimeToServerTime(stuff->timestamp);
+ configTime = ClientTimeToServerTime(stuff->configTimestamp);
+
+ if (!pScrPriv)
+ {
+ time = currentTime;
+ rep.status = RRSetConfigFailed;
+ goto sendReply;
+ }
+
+ /*
+ * Validate requested rotation
+ */
+ rotation = (Rotation) stuff->rotation;
+
+ /* test the rotation bits only! */
+ switch (rotation & 0xf) {
+ case RR_Rotate_0:
+ case RR_Rotate_90:
+ case RR_Rotate_180:
+ case RR_Rotate_270:
+ break;
+ default:
+ /*
+ * Invalid rotation
+ */
+ client->errorValue = stuff->rotation;
+ free(outputs);
+ return BadValue;
+ }
+
+ if (mode)
+ {
+ if ((~crtc->rotations) & rotation)
+ {
+ /*
+ * requested rotation or reflection not supported by screen
+ */
+ client->errorValue = stuff->rotation;
+ free(outputs);
+ return BadMatch;
+ }
+
+#ifdef RANDR_12_INTERFACE
+ /*
+ * Check screen size bounds if the DDX provides a 1.2 interface
+ * for setting screen size. Else, assume the CrtcSet sets
+ * the size along with the mode. If the driver supports transforms,
+ * then it must allow crtcs to display a subset of the screen, so
+ * only do this check for drivers without transform support.
+ */
+ if (pScrPriv->rrScreenSetSize && !crtc->transforms)
+ {
+ int source_width;
+ int source_height;
+ PictTransform transform;
+ struct pixman_f_transform f_transform, f_inverse;
+
+ RRTransformCompute (stuff->x, stuff->y,
+ mode->mode.width, mode->mode.height,
+ rotation,
+ &crtc->client_pending_transform,
+ &transform, &f_transform, &f_inverse);
+
+ RRModeGetScanoutSize (mode, &transform, &source_width, &source_height);
+ if (stuff->x + source_width > pScreen->width)
+ {
+ client->errorValue = stuff->x;
+ free(outputs);
+ return BadValue;
+ }
+
+ if (stuff->y + source_height > pScreen->height)
+ {
+ client->errorValue = stuff->y;
+ free(outputs);
+ return BadValue;
+ }
+ }
+#endif
+ }
+
+ if (!RRCrtcSet (crtc, mode, stuff->x, stuff->y,
+ rotation, numOutputs, outputs))
+ {
+ rep.status = RRSetConfigFailed;
+ goto sendReply;
+ }
+ rep.status = RRSetConfigSuccess;
+ pScrPriv->lastSetTime = time;
+
+sendReply:
+ free(outputs);
+
+ rep.type = X_Reply;
+ /* rep.status has already been filled in */
+ rep.length = 0;
+ rep.sequenceNumber = client->sequence;
+ rep.newTimestamp = pScrPriv->lastSetTime.milliseconds;
+
+ if (client->swapped)
+ {
+ int n;
+ swaps(&rep.sequenceNumber, n);
+ swapl(&rep.length, n);
+ swapl(&rep.newTimestamp, n);
+ }
+ WriteToClient(client, sizeof(xRRSetCrtcConfigReply), (char *)&rep);
+
+ return Success;
+}
+
+int
+ProcRRGetPanning (ClientPtr client)
+{
+ REQUEST(xRRGetPanningReq);
+ xRRGetPanningReply rep;
+ RRCrtcPtr crtc;
+ ScreenPtr pScreen;
+ rrScrPrivPtr pScrPriv;
+ BoxRec total;
+ BoxRec tracking;
+ INT16 border[4];
+ int n;
+
+ REQUEST_SIZE_MATCH(xRRGetPanningReq);
+ VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
+
+ /* All crtcs must be associated with screens before client
+ * requests are processed
+ */
+ pScreen = crtc->pScreen;
+ pScrPriv = rrGetScrPriv(pScreen);
+
+ if (!pScrPriv)
+ return RRErrorBase + BadRRCrtc;
+
+ memset(&rep, 0, sizeof(rep));
+ rep.type = X_Reply;
+ rep.status = RRSetConfigSuccess;
+ rep.sequenceNumber = client->sequence;
+ rep.length = 1;
+ rep.timestamp = pScrPriv->lastSetTime.milliseconds;
+
+ if (pScrPriv->rrGetPanning &&
+ pScrPriv->rrGetPanning (pScreen, crtc, &total, &tracking, border)) {
+ rep.left = total.x1;
+ rep.top = total.y1;
+ rep.width = total.x2 - total.x1;
+ rep.height = total.y2 - total.y1;
+ rep.track_left = tracking.x1;
+ rep.track_top = tracking.y1;
+ rep.track_width = tracking.x2 - tracking.x1;
+ rep.track_height = tracking.y2 - tracking.y1;
+ rep.border_left = border[0];
+ rep.border_top = border[1];
+ rep.border_right = border[2];
+ rep.border_bottom = border[3];
+ }
+
+ if (client->swapped) {
+ swaps(&rep.sequenceNumber, n);
+ swapl(&rep.length, n);
+ swaps(&rep.timestamp, n);
+ swaps(&rep.left, n);
+ swaps(&rep.top, n);
+ swaps(&rep.width, n);
+ swaps(&rep.height, n);
+ swaps(&rep.track_left, n);
+ swaps(&rep.track_top, n);
+ swaps(&rep.track_width, n);
+ swaps(&rep.track_height, n);
+ swaps(&rep.border_left, n);
+ swaps(&rep.border_top, n);
+ swaps(&rep.border_right, n);
+ swaps(&rep.border_bottom, n);
+ }
+ WriteToClient(client, sizeof(xRRGetPanningReply), (char *)&rep);
+ return Success;
+}
+
+int
+ProcRRSetPanning (ClientPtr client)
+{
+ REQUEST(xRRSetPanningReq);
+ xRRSetPanningReply rep;
+ RRCrtcPtr crtc;
+ ScreenPtr pScreen;
+ rrScrPrivPtr pScrPriv;
+ TimeStamp time;
+ BoxRec total;
+ BoxRec tracking;
+ INT16 border[4];
+ int n;
+
+ REQUEST_SIZE_MATCH(xRRSetPanningReq);
+ VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
+
+ /* All crtcs must be associated with screens before client
+ * requests are processed
+ */
+ pScreen = crtc->pScreen;
+ pScrPriv = rrGetScrPriv(pScreen);
+
+ if (!pScrPriv) {
+ time = currentTime;
+ rep.status = RRSetConfigFailed;
+ goto sendReply;
+ }
+
+ time = ClientTimeToServerTime(stuff->timestamp);
+
+ if (!pScrPriv->rrGetPanning)
+ return RRErrorBase + BadRRCrtc;
+
+ total.x1 = stuff->left;
+ total.y1 = stuff->top;
+ total.x2 = total.x1 + stuff->width;
+ total.y2 = total.y1 + stuff->height;
+ tracking.x1 = stuff->track_left;
+ tracking.y1 = stuff->track_top;
+ tracking.x2 = tracking.x1 + stuff->track_width;
+ tracking.y2 = tracking.y1 + stuff->track_height;
+ border[0] = stuff->border_left;
+ border[1] = stuff->border_top;
+ border[2] = stuff->border_right;
+ border[3] = stuff->border_bottom;
+
+ if (! pScrPriv->rrSetPanning (pScreen, crtc, &total, &tracking, border))
+ return BadMatch;
+
+ pScrPriv->lastSetTime = time;
+
+ rep.status = RRSetConfigSuccess;
+
+sendReply:
+ rep.type = X_Reply;
+ rep.sequenceNumber = client->sequence;
+ rep.length = 0;
+ rep.newTimestamp = pScrPriv->lastSetTime.milliseconds;
+
+ if (client->swapped) {
+ swaps(&rep.sequenceNumber, n);
+ swapl(&rep.length, n);
+ swaps(&rep.newTimestamp, n);
+ }
+ WriteToClient(client, sizeof(xRRSetPanningReply), (char *)&rep);
+ return Success;
+}
+
+int
+ProcRRGetCrtcGammaSize (ClientPtr client)
+{
+ REQUEST(xRRGetCrtcGammaSizeReq);
+ xRRGetCrtcGammaSizeReply reply;
+ RRCrtcPtr crtc;
+ int n;
+
+ REQUEST_SIZE_MATCH(xRRGetCrtcGammaSizeReq);
+ VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
+
+ /* Gamma retrieval failed, any better error? */
+ if (!RRCrtcGammaGet(crtc))
+ return RRErrorBase + BadRRCrtc;
+
+ reply.type = X_Reply;
+ reply.sequenceNumber = client->sequence;
+ reply.length = 0;
+ reply.size = crtc->gammaSize;
+ if (client->swapped) {
+ swaps (&reply.sequenceNumber, n);
+ swapl (&reply.length, n);
+ swaps (&reply.size, n);
+ }
+ WriteToClient (client, sizeof (xRRGetCrtcGammaSizeReply), (char *) &reply);
+ return Success;
+}
+
+int
+ProcRRGetCrtcGamma (ClientPtr client)
+{
+ REQUEST(xRRGetCrtcGammaReq);
+ xRRGetCrtcGammaReply reply;
+ RRCrtcPtr crtc;
+ int n;
+ unsigned long len;
+ char *extra = NULL;
+
+ REQUEST_SIZE_MATCH(xRRGetCrtcGammaReq);
+ VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
+
+ /* Gamma retrieval failed, any better error? */
+ if (!RRCrtcGammaGet(crtc))
+ return RRErrorBase + BadRRCrtc;
+
+ len = crtc->gammaSize * 3 * 2;
+
+ if (crtc->gammaSize) {
+ extra = malloc(len);
+ if (!extra)
+ return BadAlloc;
+ }
+
+ reply.type = X_Reply;
+ reply.sequenceNumber = client->sequence;
+ reply.length = bytes_to_int32(len);
+ reply.size = crtc->gammaSize;
+ if (client->swapped) {
+ swaps (&reply.sequenceNumber, n);
+ swapl (&reply.length, n);
+ swaps (&reply.size, n);
+ }
+ WriteToClient (client, sizeof (xRRGetCrtcGammaReply), (char *) &reply);
+ if (crtc->gammaSize)
+ {
+ memcpy(extra, crtc->gammaRed, len);
+ client->pSwapReplyFunc = (ReplySwapPtr)CopySwap16Write;
+ WriteSwappedDataToClient (client, len, extra);
+ free(extra);
+ }
+ return Success;
+}
+
+int
+ProcRRSetCrtcGamma (ClientPtr client)
+{
+ REQUEST(xRRSetCrtcGammaReq);
+ RRCrtcPtr crtc;
+ unsigned long len;
+ CARD16 *red, *green, *blue;
+
+ REQUEST_AT_LEAST_SIZE(xRRSetCrtcGammaReq);
+ VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
+
+ len = client->req_len - bytes_to_int32(sizeof (xRRSetCrtcGammaReq));
+ if (len < (stuff->size * 3 + 1) >> 1)
+ return BadLength;
+
+ if (stuff->size != crtc->gammaSize)
+ return BadMatch;
+
+ red = (CARD16 *) (stuff + 1);
+ green = red + crtc->gammaSize;
+ blue = green + crtc->gammaSize;
+
+ RRCrtcGammaSet (crtc, red, green, blue);
+
+ return Success;
+}
+
+/* Version 1.3 additions */
+
+int
+ProcRRSetCrtcTransform (ClientPtr client)
+{
+ REQUEST(xRRSetCrtcTransformReq);
+ RRCrtcPtr crtc;
+ PictTransform transform;
+ struct pixman_f_transform f_transform, f_inverse;
+ char *filter;
+ int nbytes;
+ xFixed *params;
+ int nparams;
+
+ REQUEST_AT_LEAST_SIZE(xRRSetCrtcTransformReq);
+ VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
+
+ PictTransform_from_xRenderTransform (&transform, &stuff->transform);
+ pixman_f_transform_from_pixman_transform (&f_transform, &transform);
+ if (!pixman_f_transform_invert (&f_inverse, &f_transform))
+ return BadMatch;
+
+ filter = (char *) (stuff + 1);
+ nbytes = stuff->nbytesFilter;
+ params = (xFixed *) (filter + pad_to_int32(nbytes));
+ nparams = ((xFixed *) stuff + client->req_len) - params;
+ if (nparams < 0)
+ return BadLength;
+
+ return RRCrtcTransformSet (crtc, &transform, &f_transform, &f_inverse,
+ filter, nbytes, params, nparams);
+}
+
+
+#define CrtcTransformExtra (SIZEOF(xRRGetCrtcTransformReply) - 32)
+
+static int
+transform_filter_length (RRTransformPtr transform)
+{
+ int nbytes, nparams;
+
+ if (transform->filter == NULL)
+ return 0;
+ nbytes = strlen (transform->filter->name);
+ nparams = transform->nparams;
+ return pad_to_int32(nbytes) + (nparams * sizeof (xFixed));
+}
+
+static int
+transform_filter_encode (ClientPtr client, char *output,
+ CARD16 *nbytesFilter,
+ CARD16 *nparamsFilter,
+ RRTransformPtr transform)
+{
+ int nbytes, nparams;
+ int n;
+
+ if (transform->filter == NULL) {
+ *nbytesFilter = 0;
+ *nparamsFilter = 0;
+ return 0;
+ }
+ nbytes = strlen (transform->filter->name);
+ nparams = transform->nparams;
+ *nbytesFilter = nbytes;
+ *nparamsFilter = nparams;
+ memcpy (output, transform->filter->name, nbytes);
+ while ((nbytes & 3) != 0)
+ output[nbytes++] = 0;
+ memcpy (output + nbytes, transform->params, nparams * sizeof (xFixed));
+ if (client->swapped) {
+ swaps (nbytesFilter, n);
+ swaps (nparamsFilter, n);
+ SwapLongs ((CARD32 *) (output + nbytes), nparams);
+ }
+ nbytes += nparams * sizeof (xFixed);
+ return nbytes;
+}
+
+static void
+transform_encode (ClientPtr client, xRenderTransform *wire, PictTransform *pict)
+{
+ xRenderTransform_from_PictTransform (wire, pict);
+ if (client->swapped)
+ SwapLongs ((CARD32 *) wire, bytes_to_int32(sizeof(xRenderTransform)));
+}
+
+int
+ProcRRGetCrtcTransform (ClientPtr client)
+{
+ REQUEST(xRRGetCrtcTransformReq);
+ xRRGetCrtcTransformReply *reply;
+ RRCrtcPtr crtc;
+ int n, nextra;
+ RRTransformPtr current, pending;
+ char *extra;
+
+ REQUEST_SIZE_MATCH (xRRGetCrtcTransformReq);
+ VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
+
+ pending = &crtc->client_pending_transform;
+ current = &crtc->client_current_transform;
+
+ nextra = (transform_filter_length (pending) +
+ transform_filter_length (current));
+
+ reply = malloc(sizeof (xRRGetCrtcTransformReply) + nextra);
+ if (!reply)
+ return BadAlloc;
+
+ extra = (char *) (reply + 1);
+ reply->type = X_Reply;
+ reply->sequenceNumber = client->sequence;
+ reply->length = bytes_to_int32(CrtcTransformExtra + nextra);
+
+ reply->hasTransforms = crtc->transforms;
+
+ transform_encode (client, &reply->pendingTransform, &pending->transform);
+ extra += transform_filter_encode (client, extra,
+ &reply->pendingNbytesFilter,
+ &reply->pendingNparamsFilter,
+ pending);
+
+ transform_encode (client, &reply->currentTransform, &current->transform);
+ extra += transform_filter_encode (client, extra,
+ &reply->currentNbytesFilter,
+ &reply->currentNparamsFilter,
+ current);
+
+ if (client->swapped) {
+ swaps (&reply->sequenceNumber, n);
+ swapl (&reply->length, n);
+ }
+ WriteToClient (client, sizeof (xRRGetCrtcTransformReply) + nextra, (char *) reply);
+ free(reply);
+ return Success;
+}
+
+void
+RRConstrainCursorHarder(DeviceIntPtr pDev, ScreenPtr pScreen, int mode, int *x, int *y)
+{
+ rrScrPriv (pScreen);
+ int i;
+
+ /* intentional dead space -> let it float */
+ if (pScrPriv->discontiguous)
+ return;
+
+ /* if we're moving inside a crtc, we're fine */
+ for (i = 0; i < pScrPriv->numCrtcs; i++) {
+ RRCrtcPtr crtc = pScrPriv->crtcs[i];
+
+ int left, right, top, bottom;
+
+ if (!crtc->mode)
+ continue;
+
+ crtc_bounds(crtc, &left, &right, &top, &bottom);
+
+ if ((*x >= left) && (*x <= right) && (*y >= top) && (*y <= bottom))
+ return;
+ }
+
+ /* if we're trying to escape, clamp to the CRTC we're coming from */
+ for (i = 0; i < pScrPriv->numCrtcs; i++) {
+ RRCrtcPtr crtc = pScrPriv->crtcs[i];
+ int nx, ny;
+ int left, right, top, bottom;
+
+ if (!crtc->mode)
+ continue;
+
+ crtc_bounds(crtc, &left, &right, &top, &bottom);
+ miPointerGetPosition(pDev, &nx, &ny);
+
+ if ((nx >= left) && (nx <= right) && (ny >= top) && (ny <= bottom)) {
+ if ((*x <= left) || (*x >= right)) {
+ int dx = *x - nx;
+
+ if (dx > 0)
+ *x = right;
+ else if (dx < 0)
+ *x = left;
+ }
+
+ if ((*y <= top) || (*y >= bottom)) {
+ int dy = *y - ny;
+
+ if (dy > 0)
+ *y = bottom;
+ else if (dy < 0)
+ *y = top;
+ }
+
+ return;
+ }
+ }
+}