Add support for user-defined modelines in RandR.

The RandR protocol spec has several requests in support of user-defined
modes, but the implementation was stubbed out inside the X server. Fill out
the DIX portion and start on the xf86 DDX portion. It might be necessary to
add more code to the DDX to insert the user-defined modes into the output
mode list.
(cherry picked from commit 63cc2a51ef)

Conflicts:

	randr/randrstr.h

Updated code to work in master with recent security API changes.
This commit is contained in:
Keith Packard 2007-02-18 23:49:38 -08:00 committed by Keith Packard
parent 3bffb28126
commit 2c93083edd
8 changed files with 400 additions and 50 deletions

View File

@ -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))

View File

@ -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,

View File

@ -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,

View File

@ -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);

View File

@ -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;

View File

@ -48,24 +48,12 @@ 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);
}

View File

@ -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);
}

View File

@ -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)
{