/* * 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, ¤t->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 = left; if (*x >= right) *x = right - 1; if (*y < top) *y = top; if (*y >= bottom) *y = bottom - 1; return; } } }