diff --git a/hw/xfree86/modes/xf86RandR12.c b/hw/xfree86/modes/xf86RandR12.c index ce780b6ef..73647a68b 100644 --- a/hw/xfree86/modes/xf86RandR12.c +++ b/hw/xfree86/modes/xf86RandR12.c @@ -728,6 +728,54 @@ xf86RandR12OutputSetProperty (ScreenPtr pScreen, return output->funcs->set_property(output, property, value); } +static Bool +xf86RandR12OutputValidateMode (ScreenPtr pScreen, + RROutputPtr randr_output, + RRModePtr randr_mode) +{ + xf86OutputPtr output = randr_output->devPrivate; + DisplayModePtr mode = randr_mode->devPrivate; + + if (!mode) + { + mode = xalloc (sizeof (DisplayModeRec) + randr_mode->mode.nameLength + 1); + if (!mode) + return FALSE; + mode->name = (char *) mode + 1; + memcpy (mode->name, randr_mode->name, randr_mode->mode.nameLength); + mode->name[randr_mode->mode.nameLength] = '\0'; + mode->Clock = randr_mode->mode.dotClock / 1000; + mode->HDisplay = randr_mode->mode.width; + mode->HSyncStart = randr_mode->mode.hSyncStart; + mode->HSyncEnd = randr_mode->mode.hSyncEnd; + mode->HTotal = randr_mode->mode.hTotal; + mode->HSkew = randr_mode->mode.hSkew; + + mode->VDisplay = randr_mode->mode.height; + mode->VSyncStart = randr_mode->mode.vSyncStart; + mode->VSyncEnd = randr_mode->mode.vSyncEnd; + mode->VTotal = randr_mode->mode.vTotal; + + mode->Flags = randr_mode->mode.modeFlags; + randr_mode->devPrivate = mode; + } + if (!output->funcs->mode_valid (output, mode)) + return FALSE; + return TRUE; +} + +static void +xf86RandR12ModeDestroy (ScreenPtr pScreen, RRModePtr randr_mode) +{ + DisplayModePtr mode = randr_mode->devPrivate; + + if (mode) + { + xfree (mode); + randr_mode->devPrivate = NULL; + } +} + /** * Given a list of xf86 modes and a RandR Output object, construct * RandR modes and assign them to the output @@ -958,6 +1006,8 @@ xf86RandR12Init12 (ScreenPtr pScreen) rp->rrCrtcSet = xf86RandR12CrtcSet; rp->rrCrtcSetGamma = xf86RandR12CrtcSetGamma; rp->rrOutputSetProperty = xf86RandR12OutputSetProperty; + rp->rrOutputValidateMode = xf86RandR12OutputValidateMode; + rp->rrModeDestroy = xf86RandR12ModeDestroy; rp->rrSetConfig = NULL; pScrn->PointerMoved = xf86RandR12PointerMoved; if (!xf86RandR12CreateObjects12 (pScreen)) diff --git a/randr/mirandr.c b/randr/mirandr.c index 0b763e111..47136fb96 100644 --- a/randr/mirandr.c +++ b/randr/mirandr.c @@ -73,6 +73,20 @@ miRROutputSetProperty (ScreenPtr pScreen, return TRUE; } +Bool +miRROutputValidateMode (ScreenPtr pScreen, + RROutputPtr output, + RRModePtr mode) +{ + return FALSE; +} + +void +miRRModeDestroy (ScreenPtr pScreen, + RRModePtr mode) +{ +} + /* * This function assumes that only a single depth can be * displayed at a time, but that all visuals of that depth @@ -102,7 +116,8 @@ miRandRInit (ScreenPtr pScreen) pScrPriv->rrCrtcSet = miRRCrtcSet; pScrPriv->rrCrtcSetGamma = miRRCrtcSetGamma; pScrPriv->rrOutputSetProperty = miRROutputSetProperty; - + pScrPriv->rrOutputValidateMode = miRROutputValidateMode; + pScrPriv->rrModeDestroy = miRRModeDestroy; RRScreenSetSizeRange (pScreen, pScreen->width, pScreen->height, diff --git a/randr/randrstr.h b/randr/randrstr.h index 505821269..f6d35cf1d 100644 --- a/randr/randrstr.h +++ b/randr/randrstr.h @@ -80,7 +80,7 @@ struct _rrMode { xRRModeInfo mode; char *name; void *devPrivate; - Bool userDefined; + ScreenPtr userScreen; }; struct _rrPropertyValue { @@ -135,6 +135,8 @@ struct _rrOutput { int numModes; int numPreferred; RRModePtr *modes; + int numUserModes; + RRModePtr *userModes; Bool changed; RRPropertyPtr properties; void *devPrivate; @@ -164,6 +166,13 @@ typedef Bool (*RROutputSetPropertyProcPtr) (ScreenPtr pScreen, Atom property, RRPropertyValuePtr value); +typedef Bool (*RROutputValidateModeProcPtr) (ScreenPtr pScreen, + RROutputPtr output, + RRModePtr mode); + +typedef void (*RRModeDestroyProcPtr) (ScreenPtr pScreen, + RRModePtr mode); + #endif typedef Bool (*RRGetInfoProcPtr) (ScreenPtr pScreen, Rotation *rotations); @@ -208,6 +217,8 @@ typedef struct _rrScrPriv { RRCrtcSetProcPtr rrCrtcSet; RRCrtcSetGammaProcPtr rrCrtcSetGamma; RROutputSetPropertyProcPtr rrOutputSetProperty; + RROutputValidateModeProcPtr rrOutputValidateMode; + RRModeDestroyProcPtr rrModeDestroy; #endif /* @@ -394,6 +405,15 @@ miRROutputSetProperty (ScreenPtr pScreen, Atom property, RRPropertyValuePtr value); +Bool +miRROutputValidateMode (ScreenPtr pScreen, + RROutputPtr output, + RRModePtr mode); + +void +miRRModeDestroy (ScreenPtr pScreen, + RRModePtr mode); + /* randr.c */ /* * Send all pending events @@ -549,6 +569,11 @@ Bool RRCrtcSetRotations (RRCrtcPtr crtc, Rotation rotations); +/* + * Return the area of the frame buffer scanned out by the crtc, + * taking into account the current mode and rotation + */ + void RRCrtcGetScanoutSize(RRCrtcPtr crtc, int *width, int *height); @@ -672,6 +697,14 @@ RROutputSetModes (RROutputPtr output, int numModes, int numPreferred); +int +RROutputAddUserMode (RROutputPtr output, + RRModePtr mode); + +int +RROutputDeleteUserMode (RROutputPtr output, + RRModePtr mode); + Bool RROutputSetCrtcs (RROutputPtr output, RRCrtcPtr *crtcs, diff --git a/randr/rrcrtc.c b/randr/rrcrtc.c index db506f4b0..315dd6c08 100644 --- a/randr/rrcrtc.c +++ b/randr/rrcrtc.c @@ -666,10 +666,15 @@ ProcRRSetCrtcConfig (ClientPtr client) return BadMatch; } /* validate mode for this output */ - for (j = 0; j < outputs[i]->numModes; j++) - if (outputs[i]->modes[j] == mode) + 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) + } + if (j == outputs[i]->numModes + outputs[i]->numUserModes) { if (outputs) xfree (outputs); diff --git a/randr/rrinfo.c b/randr/rrinfo.c index 797cdb1b4..549d501dc 100644 --- a/randr/rrinfo.c +++ b/randr/rrinfo.c @@ -157,9 +157,11 @@ RRScanOldConfig (ScreenPtr pScreen, Rotation rotations) pScrPriv->nSizes = 0; /* find size bounds */ - for (i = 0; i < output->numModes; i++) + for (i = 0; i < output->numModes + output->numUserModes; i++) { - RRModePtr mode = output->modes[i]; + RRModePtr mode = (i < output->numModes ? + output->modes[i] : + output->userModes[i-output->numModes]); CARD16 width = mode->mode.width; CARD16 height = mode->mode.height; diff --git a/randr/rrmode.c b/randr/rrmode.c index 261e1b75f..11175810c 100644 --- a/randr/rrmode.c +++ b/randr/rrmode.c @@ -48,25 +48,13 @@ RRModeEqual (xRRModeInfo *a, xRRModeInfo *b) static int num_modes; static RRModePtr *modes; -RRModePtr -RRModeGet (xRRModeInfo *modeInfo, - const char *name) +static RRModePtr +RRModeCreate (xRRModeInfo *modeInfo, + const char *name, + ScreenPtr userScreen) { - int i; - RRModePtr mode; - RRModePtr *newModes; - - for (i = 0; i < num_modes; i++) - { - mode = modes[i]; - if (RRModeEqual (&mode->mode, modeInfo) && - !memcmp (name, mode->name, modeInfo->nameLength)) - { - ++mode->refcnt; - return mode; - } - } - + RRModePtr mode, *newModes; + if (!RRInit ()) return NULL; @@ -78,7 +66,7 @@ RRModeGet (xRRModeInfo *modeInfo, mode->name = (char *) (mode + 1); memcpy (mode->name, name, modeInfo->nameLength); mode->name[modeInfo->nameLength] = '\0'; - mode->userDefined = FALSE; + mode->userScreen = userScreen; if (num_modes) newModes = xrealloc (modes, (num_modes + 1) * sizeof (RRModePtr)); @@ -104,11 +92,75 @@ RRModeGet (xRRModeInfo *modeInfo, return mode; } +static RRModePtr +RRModeFindByName (const char *name, + CARD16 nameLength) +{ + int i; + RRModePtr mode; + + for (i = 0; i < num_modes; i++) + { + mode = modes[i]; + if (mode->mode.nameLength == nameLength && + !memcmp (name, mode->name, nameLength)) + { + return mode; + } + } + return NULL; +} + +RRModePtr +RRModeGet (xRRModeInfo *modeInfo, + const char *name) +{ + int i; + + for (i = 0; i < num_modes; i++) + { + RRModePtr mode = modes[i]; + if (RRModeEqual (&mode->mode, modeInfo) && + !memcmp (name, mode->name, modeInfo->nameLength)) + { + ++mode->refcnt; + return mode; + } + } + + return RRModeCreate (modeInfo, name, NULL); +} + +static RRModePtr +RRModeCreateUser (ScreenPtr pScreen, + xRRModeInfo *modeInfo, + const char *name, + int *error) +{ + RRModePtr mode; + + mode = RRModeFindByName (name, modeInfo->nameLength); + if (mode) + { + *error = BadName; + return NULL; + } + + mode = RRModeCreate (modeInfo, name, pScreen); + if (!mode) + { + *error = BadAlloc; + return NULL; + } + *error = Success; + return mode; +} + RRModePtr * RRModesForScreen (ScreenPtr pScreen, int *num_ret) { rrScrPriv(pScreen); - int o, c; + int o, c, m; RRModePtr *screen_modes; int num_screen_modes = 0; @@ -122,9 +174,11 @@ RRModesForScreen (ScreenPtr pScreen, int *num_ret) RROutputPtr output = pScrPriv->outputs[o]; int m, n; - for (m = 0; m < output->numModes; m++) + for (m = 0; m < output->numModes + output->numUserModes; m++) { - RRModePtr mode = output->modes[m]; + RRModePtr mode = (m < output->numModes ? + output->modes[m] : + output->userModes[m-output->numModes]); for (n = 0; n < num_screen_modes; n++) if (screen_modes[n] == mode) break; @@ -150,6 +204,23 @@ RRModesForScreen (ScreenPtr pScreen, int *num_ret) if (n == num_screen_modes) screen_modes[num_screen_modes++] = mode; } + /* + * Add all user modes for this screen + */ + for (m = 0; m < num_modes; m++) + { + RRModePtr mode = modes[m]; + int n; + + if (mode->userScreen != pScreen) + continue; + for (n = 0; n < num_screen_modes; n++) + if (screen_modes[n] == mode) + break; + if (n == num_screen_modes) + screen_modes[num_screen_modes++] = mode; + } + *num_ret = num_screen_modes; return screen_modes; } @@ -205,38 +276,122 @@ int ProcRRCreateMode (ClientPtr client) { REQUEST(xRRCreateModeReq); + xRRCreateModeReply rep; + WindowPtr pWin; + ScreenPtr pScreen; + rrScrPrivPtr pScrPriv; + xRRModeInfo *modeInfo; + long units_after; + char *name; + int error, rc; + RRModePtr mode; - REQUEST_SIZE_MATCH(xRRCreateModeReq); - (void) stuff; - return BadImplementation; + REQUEST_AT_LEAST_SIZE (xRRCreateModeReq); + rc = dixLookupWindow(&pWin, stuff->window, client, DixReadAccess); + if (rc != Success) + return rc; + + pScreen = pWin->drawable.pScreen; + pScrPriv = rrGetScrPriv(pScreen); + + modeInfo = &stuff->modeInfo; + name = (char *) (stuff + 1); + units_after = (stuff->length - (sizeof (xRRCreateModeReq) >> 2)); + + /* check to make sure requested name fits within the data provided */ + if ((int) (modeInfo->nameLength + 3) >> 2 > units_after) + return BadLength; + + mode = RRModeCreateUser (pScreen, modeInfo, name, &error); + if (!mode) + return error; + + rep.type = X_Reply; + rep.pad0 = 0; + rep.sequenceNumber = client->sequence; + rep.length = 0; + rep.mode = mode->mode.id; + if (client->swapped) + { + int n; + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.mode, n); + } + WriteToClient(client, sizeof(xRRCreateModeReply), (char *)&rep); + + return client->noClientException; } int ProcRRDestroyMode (ClientPtr client) { REQUEST(xRRDestroyModeReq); + RRModePtr mode; REQUEST_SIZE_MATCH(xRRDestroyModeReq); - (void) stuff; - return BadImplementation; + mode = LookupIDByType (stuff->mode, RRModeType); + if (!mode) + { + client->errorValue = stuff->mode; + return RRErrorBase + BadRRMode; + } + if (!mode->userScreen) + return BadMatch; + if (mode->refcnt > 1) + return BadAccess; + FreeResource (stuff->mode, 0); + return Success; } int ProcRRAddOutputMode (ClientPtr client) { REQUEST(xRRAddOutputModeReq); + RRModePtr mode; + RROutputPtr output; REQUEST_SIZE_MATCH(xRRAddOutputModeReq); - (void) stuff; - return BadImplementation; + output = LookupOutput(client, stuff->output, DixReadAccess); + + if (!output) + { + client->errorValue = stuff->output; + return RRErrorBase + BadRROutput; + } + + mode = LookupIDByType (stuff->mode, RRModeType); + if (!mode) + { + client->errorValue = stuff->mode; + return RRErrorBase + BadRRMode; + } + + return RROutputAddUserMode (output, mode); } int ProcRRDeleteOutputMode (ClientPtr client) { REQUEST(xRRDeleteOutputModeReq); + RRModePtr mode; + RROutputPtr output; REQUEST_SIZE_MATCH(xRRDeleteOutputModeReq); - (void) stuff; - return BadImplementation; + output = LookupOutput(client, stuff->output, DixReadAccess); + + if (!output) + { + client->errorValue = stuff->output; + return RRErrorBase + BadRROutput; + } + + mode = LookupIDByType (stuff->mode, RRModeType); + if (!mode) + { + client->errorValue = stuff->mode; + return RRErrorBase + BadRRMode; + } + + return RROutputDeleteUserMode (output, mode); } diff --git a/randr/rroutput.c b/randr/rroutput.c index df1741f5c..6e95c9598 100644 --- a/randr/rroutput.c +++ b/randr/rroutput.c @@ -76,6 +76,8 @@ RROutputCreate (const char *name, output->numModes = 0; output->numPreferred = 0; output->modes = NULL; + output->numUserModes = 0; + output->userModes = NULL; output->properties = NULL; output->changed = FALSE; output->devPrivate = devPrivate; @@ -192,6 +194,74 @@ RROutputSetModes (RROutputPtr output, return TRUE; } +int +RROutputAddUserMode (RROutputPtr output, + RRModePtr mode) +{ + int m; + ScreenPtr pScreen = output->pScreen; + rrScrPriv(pScreen); + RRModePtr *newModes; + + /* Check to see if this mode is already listed for this output */ + for (m = 0; m < output->numModes + output->numUserModes; m++) + { + RRModePtr e = (m < output->numModes ? + output->modes[m] : + output->userModes[m - output->numModes]); + if (mode == e) + return Success; + } + + /* Check with the DDX to see if this mode is OK */ + if (pScrPriv->rrOutputValidateMode) + if (!pScrPriv->rrOutputValidateMode (pScreen, output, mode)) + return BadMatch; + + if (output->userModes) + newModes = xrealloc (output->userModes, + (output->numUserModes + 1) * sizeof (RRModePtr)); + else + newModes = xalloc (sizeof (RRModePtr)); + if (!newModes) + return BadAlloc; + + output->userModes = newModes; + output->userModes[output->numUserModes++] = mode; + ++mode->refcnt; + RROutputChanged (output, TRUE); + RRTellChanged (pScreen); + return Success; +} + +int +RROutputDeleteUserMode (RROutputPtr output, + RRModePtr mode) +{ + int m; + + /* Find this mode in the user mode list */ + for (m = 0; m < output->numUserModes; m++) + { + RRModePtr e = output->userModes[m]; + + if (mode == e) + break; + } + /* Not there, access error */ + if (m == output->numUserModes) + return BadAccess; + + /* make sure the mode isn't active for this output */ + if (output->crtc && output->crtc->mode == mode) + return BadMatch; + + memmove (output->userModes + m, output->userModes + m + 1, + (output->numUserModes - m - 1) * sizeof (RRModePtr)); + RRModeDestroy (mode); + return Success; +} + Bool RROutputSetCrtcs (RROutputPtr output, RRCrtcPtr *crtcs, @@ -308,9 +378,9 @@ RRDeliverOutputEvent(ClientPtr client, WindowPtr pWin, RROutputPtr output) * Destroy a Output at shutdown */ void -RROutputDestroy (RROutputPtr crtc) +RROutputDestroy (RROutputPtr output) { - FreeResource (crtc->id, 0); + FreeResource (output->id, 0); } static int @@ -318,6 +388,7 @@ RROutputDestroyResource (pointer value, XID pid) { RROutputPtr output = (RROutputPtr) value; ScreenPtr pScreen = output->pScreen; + int m; if (pScreen) { @@ -335,8 +406,15 @@ RROutputDestroyResource (pointer value, XID pid) } } } + /* XXX destroy all modes? */ if (output->modes) xfree (output->modes); + + for (m = 0; m < output->numUserModes; m++) + RRModeDestroy (output->userModes[m]); + if (output->userModes) + xfree (output->userModes); + if (output->crtcs) xfree (output->crtcs); if (output->clones) @@ -383,7 +461,10 @@ ProcRRGetOutputInfo (ClientPtr client) output = LookupOutput(client, stuff->output, DixReadAccess); if (!output) + { + client->errorValue = stuff->output; return RRErrorBase + BadRROutput; + } pScreen = output->pScreen; pScrPriv = rrGetScrPriv(pScreen); @@ -398,13 +479,13 @@ ProcRRGetOutputInfo (ClientPtr client) rep.connection = output->connection; rep.subpixelOrder = output->subpixelOrder; rep.nCrtcs = output->numCrtcs; - rep.nModes = output->numModes; + rep.nModes = output->numModes + output->numUserModes; rep.nPreferred = output->numPreferred; rep.nClones = output->numClones; rep.nameLength = output->nameLength; extraLen = ((output->numCrtcs + - output->numModes + + output->numModes + output->numUserModes + output->numClones + ((rep.nameLength + 3) >> 2)) << 2); @@ -420,7 +501,7 @@ ProcRRGetOutputInfo (ClientPtr client) crtcs = (RRCrtc *) extra; modes = (RRMode *) (crtcs + output->numCrtcs); - clones = (RROutput *) (modes + output->numModes); + clones = (RROutput *) (modes + output->numModes + output->numUserModes); name = (char *) (clones + output->numClones); for (i = 0; i < output->numCrtcs; i++) @@ -429,9 +510,12 @@ ProcRRGetOutputInfo (ClientPtr client) if (client->swapped) swapl (&crtcs[i], n); } - for (i = 0; i < output->numModes; i++) + for (i = 0; i < output->numModes + output->numUserModes; i++) { - modes[i] = output->modes[i]->mode.id; + if (i < output->numModes) + modes[i] = output->modes[i]->mode.id; + else + modes[i] = output->userModes[i - output->numModes]->mode.id; if (client->swapped) swapl (&modes[i], n); } diff --git a/randr/rrscreen.c b/randr/rrscreen.c index 168000351..ad74ac3af 100644 --- a/randr/rrscreen.c +++ b/randr/rrscreen.c @@ -473,7 +473,7 @@ RR10GetData (ScreenPtr pScreen, RROutputPtr output) { RR10DataPtr data; RRScreenSizePtr size; - int nmode = output->numModes; + int nmode = output->numModes + output->numUserModes; int o, os, l, r; RRScreenRatePtr refresh; CARD16 vRefresh; @@ -500,11 +500,14 @@ RR10GetData (ScreenPtr pScreen, RROutputPtr output) /* * find modes not yet listed */ - for (o = 0; o < output->numModes; o++) + for (o = 0; o < output->numModes + output->numUserModes; o++) { if (used[o]) continue; - mode = output->modes[o]; + if (o < output->numModes) + mode = output->modes[o]; + else + mode = output->userModes[o - output->numModes]; l = data->nsize; size[l].id = data->nsize; @@ -524,9 +527,12 @@ RR10GetData (ScreenPtr pScreen, RROutputPtr output) /* * Find all modes with matching size */ - for (os = o; os < output->numModes; os++) + for (os = o; os < output->numModes + output->numUserModes; os++) { - mode = output->modes[os]; + if (os < output->numModes) + mode = output->modes[os]; + else + mode = output->userModes[os - output->numModes]; if (mode->mode.width == size[l].width && mode->mode.height == size[l].height) {