diff options
author | Kaleb Keithley <kaleb@freedesktop.org> | 2003-11-14 16:48:57 +0000 |
---|---|---|
committer | Kaleb Keithley <kaleb@freedesktop.org> | 2003-11-14 16:48:57 +0000 |
commit | 9508a382f8a9f241dab097d921b6d290c1c3a776 (patch) | |
tree | fa456480bae7040c3f971a70b390f2d091c680b5 /randr/randr.c | |
parent | ded6147bfb5d75ff1e67c858040a628b61bc17d1 (diff) |
Initial revision
Diffstat (limited to 'randr/randr.c')
-rw-r--r-- | randr/randr.c | 1197 |
1 files changed, 1197 insertions, 0 deletions
diff --git a/randr/randr.c b/randr/randr.c new file mode 100644 index 000000000..666605e96 --- /dev/null +++ b/randr/randr.c @@ -0,0 +1,1197 @@ +/* + * $XFree86: xc/programs/Xserver/randr/randr.c,v 1.19 2003/02/08 03:52:30 dawes Exp $ + * + * Copyright © 2000, Compaq Computer Corporation, + * Copyright © 2002, Hewlett Packard, 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 Compaq or HP not be used in advertising + * or publicity pertaining to distribution of the software without specific, + * written prior permission. HP makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + * + * HP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL HP + * 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. + * + * Author: Jim Gettys, HP Labs, Hewlett-Packard, Inc. + */ + + +#define NEED_REPLIES +#define NEED_EVENTS +#include "X.h" +#include "Xproto.h" +#include "misc.h" +#include "os.h" +#include "dixstruct.h" +#include "resource.h" +#include "scrnintstr.h" +#include "windowstr.h" +#include "pixmapstr.h" +#include "extnsionst.h" +#include "servermd.h" +#include "randr.h" +#include "randrproto.h" +#include "randrstr.h" +#include "render.h" /* we share subpixel order information */ +#include "picturestr.h" +#include "Xfuncproto.h" +#ifdef EXTMODULE +#include "xf86_ansic.h" +#endif + +#define RR_VALIDATE +int RRGeneration; +int RRNScreens; + +static int ProcRRQueryVersion (ClientPtr pClient); +static int ProcRRDispatch (ClientPtr pClient); +static int SProcRRDispatch (ClientPtr pClient); +static int SProcRRQueryVersion (ClientPtr pClient); + +#define wrap(priv,real,mem,func) {\ + priv->mem = real->mem; \ + real->mem = func; \ +} + +#define unwrap(priv,real,mem) {\ + real->mem = priv->mem; \ +} + +static CARD8 RRReqCode; +static int RRErrBase; +static int RREventBase; +static RESTYPE ClientType, EventType; /* resource types for event masks */ +static int RRClientPrivateIndex; + +typedef struct _RRTimes { + TimeStamp setTime; + TimeStamp configTime; +} RRTimesRec, *RRTimesPtr; + +typedef struct _RRClient { + int major_version; + int minor_version; +/* RRTimesRec times[0]; */ +} RRClientRec, *RRClientPtr; + +/* + * each window has a list of clients requesting + * RRNotify events. Each client has a resource + * for each window it selects RRNotify input for, + * this resource is used to delete the RRNotifyRec + * entry from the per-window queue. + */ + +typedef struct _RREvent *RREventPtr; + +typedef struct _RREvent { + RREventPtr next; + ClientPtr client; + WindowPtr window; + XID clientResource; + int mask; +} RREventRec; + +int rrPrivIndex = -1; + +#define GetRRClient(pClient) ((RRClientPtr) (pClient)->devPrivates[RRClientPrivateIndex].ptr) +#define rrClientPriv(pClient) RRClientPtr pRRClient = GetRRClient(pClient) + +static Bool +RRClientKnowsRates (ClientPtr pClient) +{ + rrClientPriv(pClient); + + return (pRRClient->major_version > 1 || + (pRRClient->major_version == 1 && pRRClient->minor_version >= 1)); +} + +static void +RRClientCallback (CallbackListPtr *list, + pointer closure, + pointer data) +{ + NewClientInfoRec *clientinfo = (NewClientInfoRec *) data; + ClientPtr pClient = clientinfo->client; + rrClientPriv(pClient); + RRTimesPtr pTimes = (RRTimesPtr) (pRRClient + 1); + int i; + + pRRClient->major_version = 0; + pRRClient->minor_version = 0; + for (i = 0; i < screenInfo.numScreens; i++) + { + ScreenPtr pScreen = screenInfo.screens[i]; + rrScrPriv(pScreen); + + if (pScrPriv) + { + pTimes[i].setTime = pScrPriv->lastSetTime; + pTimes[i].configTime = pScrPriv->lastConfigTime; + } + } +} + +static void +RRResetProc (ExtensionEntry *extEntry) +{ +} + +static Bool +RRCloseScreen (int i, ScreenPtr pScreen) +{ + rrScrPriv(pScreen); + + unwrap (pScrPriv, pScreen, CloseScreen); + if (pScrPriv->pSizes) + xfree (pScrPriv->pSizes); + xfree (pScrPriv); + RRNScreens -= 1; /* ok, one fewer screen with RandR running */ + return (*pScreen->CloseScreen) (i, pScreen); +} + +static void +SRRScreenChangeNotifyEvent(xRRScreenChangeNotifyEvent *from, + xRRScreenChangeNotifyEvent *to) +{ + to->type = from->type; + to->rotation = from->rotation; + cpswaps(from->sequenceNumber, to->sequenceNumber); + cpswapl(from->timestamp, to->timestamp); + cpswapl(from->configTimestamp, to->configTimestamp); + cpswapl(from->root, to->root); + cpswapl(from->window, to->window); + cpswaps(from->sizeID, to->sizeID); + cpswaps(from->widthInPixels, to->widthInPixels); + cpswaps(from->heightInPixels, to->heightInPixels); + cpswaps(from->widthInMillimeters, to->widthInMillimeters); + cpswaps(from->heightInMillimeters, to->heightInMillimeters); + cpswaps(from->subpixelOrder, to->subpixelOrder); +} + +Bool RRScreenInit(ScreenPtr pScreen) +{ + rrScrPrivPtr pScrPriv; + + if (RRGeneration != serverGeneration) + { + if ((rrPrivIndex = AllocateScreenPrivateIndex()) < 0) + return FALSE; + RRGeneration = serverGeneration; + } + + pScrPriv = (rrScrPrivPtr) xalloc (sizeof (rrScrPrivRec)); + if (!pScrPriv) + return FALSE; + + SetRRScreen(pScreen, pScrPriv); + + /* + * Calling function best set these function vectors + */ + pScrPriv->rrSetConfig = 0; + pScrPriv->rrGetInfo = 0; + /* + * This value doesn't really matter -- any client must call + * GetScreenInfo before reading it which will automatically update + * the time + */ + pScrPriv->lastSetTime = currentTime; + pScrPriv->lastConfigTime = currentTime; + + wrap (pScrPriv, pScreen, CloseScreen, RRCloseScreen); + + pScrPriv->rotations = RR_Rotate_0; + + pScrPriv->nSizes = 0; + pScrPriv->nSizesInUse = 0; + pScrPriv->pSizes = 0; + + pScrPriv->rotation = RR_Rotate_0; + pScrPriv->size = -1; + + RRNScreens += 1; /* keep count of screens that implement randr */ + return TRUE; +} + +/*ARGSUSED*/ +static int +RRFreeClient (pointer data, XID id) +{ + RREventPtr pRREvent; + WindowPtr pWin; + RREventPtr *pHead, pCur, pPrev; + + pRREvent = (RREventPtr) data; + pWin = pRREvent->window; + pHead = (RREventPtr *) LookupIDByType(pWin->drawable.id, EventType); + if (pHead) { + pPrev = 0; + for (pCur = *pHead; pCur && pCur != pRREvent; pCur=pCur->next) + pPrev = pCur; + if (pCur) + { + if (pPrev) + pPrev->next = pRREvent->next; + else + *pHead = pRREvent->next; + } + } + xfree ((pointer) pRREvent); + return 1; +} + +/*ARGSUSED*/ +static int +RRFreeEvents (pointer data, XID id) +{ + RREventPtr *pHead, pCur, pNext; + + pHead = (RREventPtr *) data; + for (pCur = *pHead; pCur; pCur = pNext) { + pNext = pCur->next; + FreeResource (pCur->clientResource, ClientType); + xfree ((pointer) pCur); + } + xfree ((pointer) pHead); + return 1; +} + +void +RRExtensionInit (void) +{ + ExtensionEntry *extEntry; + + if (RRNScreens == 0) return; + + RRClientPrivateIndex = AllocateClientPrivateIndex (); + if (!AllocateClientPrivate (RRClientPrivateIndex, + sizeof (RRClientRec) + + screenInfo.numScreens * sizeof (RRTimesRec))) + return; + if (!AddCallback (&ClientStateCallback, RRClientCallback, 0)) + return; + + ClientType = CreateNewResourceType(RRFreeClient); + if (!ClientType) + return; + EventType = CreateNewResourceType(RRFreeEvents); + if (!EventType) + return; + extEntry = AddExtension (RANDR_NAME, RRNumberEvents, RRNumberErrors, + ProcRRDispatch, SProcRRDispatch, + RRResetProc, StandardMinorOpcode); + if (!extEntry) + return; + RRReqCode = (CARD8) extEntry->base; + RRErrBase = extEntry->errorBase; + RREventBase = extEntry->eventBase; + EventSwapVector[RREventBase + RRScreenChangeNotify] = (EventSwapPtr) + SRRScreenChangeNotifyEvent; + + return; +} + +static int +TellChanged (WindowPtr pWin, pointer value) +{ + RREventPtr *pHead, pRREvent; + ClientPtr client; + xRRScreenChangeNotifyEvent se; + ScreenPtr pScreen = pWin->drawable.pScreen; + rrScrPriv(pScreen); + RRScreenSizePtr pSize; + WindowPtr pRoot = WindowTable[pScreen->myNum]; + + pHead = (RREventPtr *) LookupIDByType (pWin->drawable.id, EventType); + if (!pHead) + return WT_WALKCHILDREN; + + se.type = RRScreenChangeNotify + RREventBase; + se.rotation = (CARD8) pScrPriv->rotation; + se.timestamp = pScrPriv->lastSetTime.milliseconds; + se.configTimestamp = pScrPriv->lastConfigTime.milliseconds; + se.root = pRoot->drawable.id; + se.window = pWin->drawable.id; + se.subpixelOrder = PictureGetSubpixelOrder (pScreen); + if (pScrPriv->size >= 0) + { + pSize = &pScrPriv->pSizes[pScrPriv->size]; + se.sizeID = pSize->id; + se.widthInPixels = pSize->width; + se.heightInPixels = pSize->height; + se.widthInMillimeters = pSize->mmWidth; + se.heightInMillimeters = pSize->mmHeight; + } + else + { + /* + * This "shouldn't happen", but a broken DDX can + * forget to set the current configuration on GetInfo + */ + se.sizeID = 0xffff; + se.widthInPixels = 0; + se.heightInPixels = 0; + se.widthInMillimeters = 0; + se.heightInMillimeters = 0; + } + for (pRREvent = *pHead; pRREvent; pRREvent = pRREvent->next) + { + client = pRREvent->client; + if (client == serverClient || client->clientGone) + continue; + se.sequenceNumber = client->sequence; + if(pRREvent->mask & RRScreenChangeNotifyMask) + WriteEventsToClient (client, 1, (xEvent *) &se); + } + return WT_WALKCHILDREN; +} + +static Bool +RRGetInfo (ScreenPtr pScreen) +{ + rrScrPriv (pScreen); + int i, j, k, l; + Bool changed; + Rotation rotations; + RRScreenSizePtr pSize; + RRScreenRatePtr pRate; + + for (i = 0; i < pScrPriv->nSizes; i++) + { + pSize = &pScrPriv->pSizes[i]; + pSize->oldReferenced = pSize->referenced; + pSize->referenced = FALSE; + for (k = 0; k < pSize->nRates; k++) + { + pRate = &pSize->pRates[k]; + pRate->oldReferenced = pRate->referenced; + pRate->referenced = FALSE; + } + } + if (!(*pScrPriv->rrGetInfo) (pScreen, &rotations)) + return FALSE; + + changed = FALSE; + + /* + * Check whether anything changed and simultaneously generate + * the protocol id values for the objects + */ + if (rotations != pScrPriv->rotations) + { + pScrPriv->rotations = rotations; + changed = TRUE; + } + + j = 0; + for (i = 0; i < pScrPriv->nSizes; i++) + { + pSize = &pScrPriv->pSizes[i]; + if (pSize->oldReferenced != pSize->referenced) + changed = TRUE; + if (pSize->referenced) + pSize->id = j++; + l = 0; + for (k = 0; k < pSize->nRates; k++) + { + pRate = &pSize->pRates[k]; + if (pRate->oldReferenced != pRate->referenced) + changed = TRUE; + if (pRate->referenced) + l++; + } + pSize->nRatesInUse = l; + } + pScrPriv->nSizesInUse = j; + if (changed) + { + UpdateCurrentTime (); + pScrPriv->lastConfigTime = currentTime; + WalkTree (pScreen, TellChanged, (pointer) pScreen); + } + return TRUE; +} + +static void +RRSendConfigNotify (ScreenPtr pScreen) +{ + WindowPtr pWin = WindowTable[pScreen->myNum]; + xEvent event; + + event.u.u.type = ConfigureNotify; + event.u.configureNotify.window = pWin->drawable.id; + event.u.configureNotify.aboveSibling = None; + event.u.configureNotify.x = 0; + event.u.configureNotify.y = 0; + + /* XXX xinerama stuff ? */ + + event.u.configureNotify.width = pWin->drawable.width; + event.u.configureNotify.height = pWin->drawable.height; + event.u.configureNotify.borderWidth = wBorderWidth (pWin); + event.u.configureNotify.override = pWin->overrideRedirect; + DeliverEvents(pWin, &event, 1, NullWindow); +} + +static int +ProcRRQueryVersion (ClientPtr client) +{ + xRRQueryVersionReply rep; + register int n; + REQUEST(xRRQueryVersionReq); + rrClientPriv(client); + + REQUEST_SIZE_MATCH(xRRQueryVersionReq); + pRRClient->major_version = stuff->majorVersion; + pRRClient->minor_version = stuff->minorVersion; + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.majorVersion = RANDR_MAJOR; + rep.minorVersion = RANDR_MINOR; + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.majorVersion, n); + swapl(&rep.minorVersion, n); + } + WriteToClient(client, sizeof(xRRQueryVersionReply), (char *)&rep); + return (client->noClientException); +} + + +extern char *ConnectionInfo; + +static int padlength[4] = {0, 3, 2, 1}; + +static void +RREditConnectionInfo (ScreenPtr pScreen) +{ + xConnSetup *connSetup; + char *vendor; + xPixmapFormat *formats; + xWindowRoot *root; + xDepth *depth; + xVisualType *visual; + int screen = 0; + int d; + + connSetup = (xConnSetup *) ConnectionInfo; + vendor = (char *) connSetup + sizeof (xConnSetup); + formats = (xPixmapFormat *) ((char *) vendor + + connSetup->nbytesVendor + + padlength[connSetup->nbytesVendor & 3]); + root = (xWindowRoot *) ((char *) formats + + sizeof (xPixmapFormat) * screenInfo.numPixmapFormats); + while (screen != pScreen->myNum) + { + depth = (xDepth *) ((char *) root + + sizeof (xWindowRoot)); + for (d = 0; d < root->nDepths; d++) + { + visual = (xVisualType *) ((char *) depth + + sizeof (xDepth)); + depth = (xDepth *) ((char *) visual + + depth->nVisuals * sizeof (xVisualType)); + } + root = (xWindowRoot *) ((char *) depth); + screen++; + } + root->pixWidth = pScreen->width; + root->pixHeight = pScreen->height; + root->mmWidth = pScreen->mmWidth; + root->mmHeight = pScreen->mmHeight; +} + +static int +ProcRRGetScreenInfo (ClientPtr client) +{ + REQUEST(xRRGetScreenInfoReq); + xRRGetScreenInfoReply rep; + WindowPtr pWin; + int n; + ScreenPtr pScreen; + rrScrPrivPtr pScrPriv; + CARD8 *extra; + int extraLen; + + REQUEST_SIZE_MATCH(xRRGetScreenInfoReq); + pWin = (WindowPtr)SecurityLookupWindow(stuff->window, client, + SecurityReadAccess); + + if (!pWin) + return BadWindow; + + pScreen = pWin->drawable.pScreen; + pScrPriv = rrGetScrPriv(pScreen); + rep.pad = 0; + if (!pScrPriv) + { + rep.type = X_Reply; + rep.setOfRotations = RR_Rotate_0;; + rep.sequenceNumber = client->sequence; + rep.length = 0; + rep.root = WindowTable[pWin->drawable.pScreen->myNum]->drawable.id; + rep.timestamp = currentTime.milliseconds; + rep.configTimestamp = currentTime.milliseconds; + rep.nSizes = 0; + rep.sizeID = 0; + rep.rotation = RR_Rotate_0; + rep.rate = 0; + rep.nrateEnts = 0; + extra = 0; + extraLen = 0; + } + else + { + int i, j; + xScreenSizes *size; + CARD16 *rates; + CARD8 *data8; + Bool has_rate = RRClientKnowsRates (client); + + RRGetInfo (pScreen); + + rep.type = X_Reply; + rep.setOfRotations = pScrPriv->rotations; + rep.sequenceNumber = client->sequence; + rep.length = 0; + rep.root = WindowTable[pWin->drawable.pScreen->myNum]->drawable.id; + rep.timestamp = pScrPriv->lastSetTime.milliseconds; + rep.configTimestamp = pScrPriv->lastConfigTime.milliseconds; + rep.rotation = pScrPriv->rotation; + rep.nSizes = pScrPriv->nSizesInUse; + rep.rate = pScrPriv->rate; + rep.nrateEnts = 0; + if (has_rate) + { + for (i = 0; i < pScrPriv->nSizes; i++) + { + RRScreenSizePtr pSize = &pScrPriv->pSizes[i]; + if (pSize->referenced) + { + rep.nrateEnts += (1 + pSize->nRatesInUse); + } + } + } + + if (pScrPriv->size >= 0) + rep.sizeID = pScrPriv->pSizes[pScrPriv->size].id; + else + return BadImplementation; + + extraLen = (rep.nSizes * sizeof (xScreenSizes) + + rep.nrateEnts * sizeof (CARD16)); + + extra = (CARD8 *) xalloc (extraLen); + if (!extra) + return BadAlloc; + /* + * First comes the size information + */ + size = (xScreenSizes *) extra; + rates = (CARD16 *) (size + rep.nSizes); + for (i = 0; i < pScrPriv->nSizes; i++) + { + RRScreenSizePtr pSize = &pScrPriv->pSizes[i]; + if (pSize->referenced) + { + size->widthInPixels = pSize->width; + size->heightInPixels = pSize->height; + size->widthInMillimeters = pSize->mmWidth; + size->heightInMillimeters = pSize->mmHeight; + if (client->swapped) + { + swaps (&size->widthInPixels, n); + swaps (&size->heightInPixels, n); + swaps (&size->widthInMillimeters, n); + swaps (&size->heightInMillimeters, n); + } + size++; + if (has_rate) + { + *rates = pSize->nRatesInUse; + if (client->swapped) + { + swaps (rates, n); + } + rates++; + for (j = 0; j < pSize->nRates; j++) + { + RRScreenRatePtr pRate = &pSize->pRates[j]; + if (pRate->referenced) + { + *rates = pRate->rate; + if (client->swapped) + { + swaps (rates, n); + } + rates++; + } + } + } + } + } + data8 = (CARD8 *) rates; + + if (data8 - (CARD8 *) extra != extraLen) + FatalError ("RRGetScreenInfo bad extra len %d != %d\n", + data8 - (CARD8 *) extra, extraLen); + rep.length = (extraLen + 3) >> 2; + } + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.timestamp, n); + swaps(&rep.rotation, n); + swaps(&rep.nSizes, n); + swaps(&rep.sizeID, n); + swaps(&rep.rate, n); + swaps(&rep.nrateEnts, n); + } + WriteToClient(client, sizeof(xRRGetScreenInfoReply), (char *)&rep); + if (extraLen) + { + WriteToClient (client, extraLen, (char *) extra); + xfree (extra); + } + return (client->noClientException); +} + +static int +ProcRRSetScreenConfig (ClientPtr client) +{ + REQUEST(xRRSetScreenConfigReq); + xRRSetScreenConfigReply rep; + DrawablePtr pDraw; + int n; + ScreenPtr pScreen; + rrScrPrivPtr pScrPriv; + TimeStamp configTime; + TimeStamp time; + RRScreenSizePtr pSize; + int i; + Rotation rotation; + int rate; + short oldWidth, oldHeight; + Bool has_rate; + + UpdateCurrentTime (); + + if (RRClientKnowsRates (client)) + { + REQUEST_SIZE_MATCH (xRRSetScreenConfigReq); + has_rate = TRUE; + } + else + { + REQUEST_SIZE_MATCH (xRR1_0SetScreenConfigReq); + has_rate = FALSE; + } + + SECURITY_VERIFY_DRAWABLE(pDraw, stuff->drawable, client, + SecurityWriteAccess); + + pScreen = pDraw->pScreen; + + pScrPriv= rrGetScrPriv(pScreen); + + time = ClientTimeToServerTime(stuff->timestamp); + configTime = ClientTimeToServerTime(stuff->configTimestamp); + + oldWidth = pScreen->width; + oldHeight = pScreen->height; + + if (!pScrPriv) + { + time = currentTime; + rep.status = RRSetConfigFailed; + goto sendReply; + } + if (!RRGetInfo (pScreen)) + return BadAlloc; + + /* + * if the client's config timestamp is not the same as the last config + * timestamp, then the config information isn't up-to-date and + * can't even be validated + */ + if (CompareTimeStamps (configTime, pScrPriv->lastConfigTime) != 0) + { + rep.status = RRSetConfigInvalidConfigTime; + goto sendReply; + } + + /* + * Search for the requested size + */ + pSize = 0; + for (i = 0; i < pScrPriv->nSizes; i++) + { + pSize = &pScrPriv->pSizes[i]; + if (pSize->referenced && pSize->id == stuff->sizeID) + { + break; + } + } + if (i == pScrPriv->nSizes) + { + /* + * Invalid size ID + */ + client->errorValue = stuff->sizeID; + return BadValue; + } + + /* + * 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; + return BadValue; + } + + if ((~pScrPriv->rotations) & rotation) + { + /* + * requested rotation or reflection not supported by screen + */ + client->errorValue = stuff->rotation; + return BadMatch; + } + + /* + * Validate requested refresh + */ + if (has_rate) + rate = (int) stuff->rate; + else + rate = 0; + + if (rate) + { + for (i = 0; i < pSize->nRates; i++) + { + RRScreenRatePtr pRate = &pSize->pRates[i]; + if (pRate->referenced && pRate->rate == rate) + break; + } + if (i == pSize->nRates) + { + /* + * Invalid rate + */ + client->errorValue = rate; + return BadValue; + } + } + + /* + * Make sure the requested set-time is not older than + * the last set-time + */ + if (CompareTimeStamps (time, pScrPriv->lastSetTime) < 0) + { + rep.status = RRSetConfigInvalidTime; + goto sendReply; + } + + /* + * call out to ddx routine to effect the change + */ + if (!(*pScrPriv->rrSetConfig) (pScreen, rotation, rate, + pSize)) + { + /* + * unknown DDX failure, report to client + */ + rep.status = RRSetConfigFailed; + goto sendReply; + } + + /* + * set current extension configuration pointers + */ + RRSetCurrentConfig (pScreen, rotation, rate, pSize); + + /* + * Deliver ScreenChangeNotify events whenever + * the configuration is updated + */ + WalkTree (pScreen, TellChanged, (pointer) pScreen); + + /* + * Deliver ConfigureNotify events when root changes + * pixel size + */ + if (oldWidth != pScreen->width || oldHeight != pScreen->height) + RRSendConfigNotify (pScreen); + RREditConnectionInfo (pScreen); + + /* + * Fix pointer bounds and location + */ + ScreenRestructured (pScreen); + pScrPriv->lastSetTime = time; + + /* + * Report Success + */ + rep.status = RRSetConfigSuccess; + +sendReply: + + rep.type = X_Reply; + /* rep.status has already been filled in */ + rep.length = 0; + rep.sequenceNumber = client->sequence; + + rep.newTimestamp = pScrPriv->lastSetTime.milliseconds; + rep.newConfigTimestamp = pScrPriv->lastConfigTime.milliseconds; + rep.root = WindowTable[pDraw->pScreen->myNum]->drawable.id; + + if (client->swapped) + { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.newTimestamp, n); + swapl(&rep.newConfigTimestamp, n); + swapl(&rep.root, n); + } + WriteToClient(client, sizeof(xRRSetScreenConfigReply), (char *)&rep); + + return (client->noClientException); +} + +static int +ProcRRSelectInput (ClientPtr client) +{ + REQUEST(xRRSelectInputReq); + rrClientPriv(client); + RRTimesPtr pTimes; + WindowPtr pWin; + RREventPtr pRREvent, pNewRREvent, *pHead; + XID clientResource; + + REQUEST_SIZE_MATCH(xRRSelectInputReq); + pWin = SecurityLookupWindow (stuff->window, client, SecurityWriteAccess); + if (!pWin) + return BadWindow; + pHead = (RREventPtr *)SecurityLookupIDByType(client, + pWin->drawable.id, EventType, + SecurityWriteAccess); + + if (stuff->enable & (RRScreenChangeNotifyMask)) + { + ScreenPtr pScreen = pWin->drawable.pScreen; + rrScrPriv (pScreen); + + if (pHead) + { + /* check for existing entry. */ + for (pRREvent = *pHead; pRREvent; pRREvent = pRREvent->next) + if (pRREvent->client == client) + return Success; + } + + /* build the entry */ + pNewRREvent = (RREventPtr) xalloc (sizeof (RREventRec)); + if (!pNewRREvent) + return BadAlloc; + pNewRREvent->next = 0; + pNewRREvent->client = client; + pNewRREvent->window = pWin; + pNewRREvent->mask = stuff->enable; + /* + * add a resource that will be deleted when + * the client goes away + */ + clientResource = FakeClientID (client->index); + pNewRREvent->clientResource = clientResource; + if (!AddResource (clientResource, ClientType, (pointer)pNewRREvent)) + return BadAlloc; + /* + * create a resource to contain a pointer to the list + * of clients selecting input. This must be indirect as + * the list may be arbitrarily rearranged which cannot be + * done through the resource database. + */ + if (!pHead) + { + pHead = (RREventPtr *) xalloc (sizeof (RREventPtr)); + if (!pHead || + !AddResource (pWin->drawable.id, EventType, (pointer)pHead)) + { + FreeResource (clientResource, RT_NONE); + return BadAlloc; + } + *pHead = 0; + } + pNewRREvent->next = *pHead; + *pHead = pNewRREvent; + /* + * Now see if the client needs an event + */ + if (pScrPriv) + { + pTimes = &((RRTimesPtr) (pRRClient + 1))[pScreen->myNum]; + if (CompareTimeStamps (pTimes->setTime, + pScrPriv->lastSetTime) != 0 || + CompareTimeStamps (pTimes->configTime, + pScrPriv->lastConfigTime) != 0) + { + TellChanged (pWin, (pointer) pScreen); + } + } + } + else if (stuff->enable == xFalse) + { + /* delete the interest */ + if (pHead) { + pNewRREvent = 0; + for (pRREvent = *pHead; pRREvent; pRREvent = pRREvent->next) { + if (pRREvent->client == client) + break; + pNewRREvent = pRREvent; + } + if (pRREvent) { + FreeResource (pRREvent->clientResource, ClientType); + if (pNewRREvent) + pNewRREvent->next = pRREvent->next; + else + *pHead = pRREvent->next; + xfree (pRREvent); + } + } + } + else + { + client->errorValue = stuff->enable; + return BadValue; + } + return Success; +} + + +static int +ProcRRDispatch (ClientPtr client) +{ + REQUEST(xReq); + switch (stuff->data) + { + case X_RRQueryVersion: + return ProcRRQueryVersion(client); + case X_RRSetScreenConfig: + return ProcRRSetScreenConfig(client); + case X_RRSelectInput: + return ProcRRSelectInput(client); + case X_RRGetScreenInfo: + return ProcRRGetScreenInfo(client); + default: + return BadRequest; + } +} + +static int +SProcRRQueryVersion (ClientPtr client) +{ + register int n; + REQUEST(xRRQueryVersionReq); + + swaps(&stuff->length, n); + swapl(&stuff->majorVersion, n); + swapl(&stuff->minorVersion, n); + return ProcRRQueryVersion(client); +} + +static int +SProcRRGetScreenInfo (ClientPtr client) +{ + register int n; + REQUEST(xRRGetScreenInfoReq); + + swaps(&stuff->length, n); + swapl(&stuff->window, n); + return ProcRRGetScreenInfo(client); +} + +static int +SProcRRSetScreenConfig (ClientPtr client) +{ + register int n; + REQUEST(xRRSetScreenConfigReq); + + if (RRClientKnowsRates (client)) + { + REQUEST_SIZE_MATCH (xRRSetScreenConfigReq); + swaps (&stuff->rate, n); + } + else + { + REQUEST_SIZE_MATCH (xRR1_0SetScreenConfigReq); + } + + swaps(&stuff->length, n); + swapl(&stuff->drawable, n); + swapl(&stuff->timestamp, n); + swaps(&stuff->sizeID, n); + swaps(&stuff->rotation, n); + return ProcRRSetScreenConfig(client); +} + +static int +SProcRRSelectInput (ClientPtr client) +{ + register int n; + REQUEST(xRRSelectInputReq); + + swaps(&stuff->length, n); + swapl(&stuff->window, n); + return ProcRRSelectInput(client); +} + + +static int +SProcRRDispatch (ClientPtr client) +{ + REQUEST(xReq); + switch (stuff->data) + { + case X_RRQueryVersion: + return SProcRRQueryVersion(client); + case X_RRSetScreenConfig: + return SProcRRSetScreenConfig(client); + case X_RRSelectInput: + return SProcRRSelectInput(client); + case X_RRGetScreenInfo: + return SProcRRGetScreenInfo(client); + default: + return BadRequest; + } +} + + +static Bool +RRScreenSizeMatches (RRScreenSizePtr a, + RRScreenSizePtr b) +{ + if (a->width != b->width) + return FALSE; + if (a->height != b->height) + return FALSE; + if (a->mmWidth != b->mmWidth) + return FALSE; + if (a->mmHeight != b->mmHeight) + return FALSE; + return TRUE; +} + +RRScreenSizePtr +RRRegisterSize (ScreenPtr pScreen, + short width, + short height, + short mmWidth, + short mmHeight) +{ + rrScrPriv (pScreen); + int i; + RRScreenSize tmp; + RRScreenSizePtr pNew; + + if (!pScrPriv) + return 0; + + tmp.width = width; + tmp.height= height; + tmp.mmWidth = mmWidth; + tmp.mmHeight = mmHeight; + tmp.pRates = 0; + tmp.nRates = 0; + tmp.nRatesInUse = 0; + tmp.referenced = TRUE; + tmp.oldReferenced = FALSE; + for (i = 0; i < pScrPriv->nSizes; i++) + if (RRScreenSizeMatches (&tmp, &pScrPriv->pSizes[i])) + { + pScrPriv->pSizes[i].referenced = TRUE; + return &pScrPriv->pSizes[i]; + } + pNew = xrealloc (pScrPriv->pSizes, + (pScrPriv->nSizes + 1) * sizeof (RRScreenSize)); + if (!pNew) + return 0; + pNew[pScrPriv->nSizes++] = tmp; + pScrPriv->pSizes = pNew; + return &pNew[pScrPriv->nSizes-1]; +} + +Bool RRRegisterRate (ScreenPtr pScreen, + RRScreenSizePtr pSize, + int rate) +{ + rrScrPriv(pScreen); + int i; + RRScreenRatePtr pNew, pRate; + + if (!pScrPriv) + return FALSE; + + for (i = 0; i < pSize->nRates; i++) + { + pRate = &pSize->pRates[i]; + if (pRate->rate == rate) + { + pRate->referenced = TRUE; + return TRUE; + } + } + + pNew = xrealloc (pSize->pRates, + (pSize->nRates + 1) * sizeof (RRScreenRate)); + if (!pNew) + return FALSE; + pRate = &pNew[pSize->nRates++]; + pRate->rate = rate; + pRate->referenced = TRUE; + pRate->oldReferenced = FALSE; + pSize->pRates = pNew; + return TRUE; +} + +void +RRSetCurrentConfig (ScreenPtr pScreen, + Rotation rotation, + int rate, + RRScreenSizePtr pSize) +{ + rrScrPriv (pScreen); + + if (!pScrPriv) + return; + + pScrPriv->rotation = rotation; + pScrPriv->size = pSize - pScrPriv->pSizes; + pScrPriv->rate = rate; +} |