summaryrefslogtreecommitdiff
path: root/randr/randr.c
diff options
context:
space:
mode:
authorKaleb Keithley <kaleb@freedesktop.org>2003-11-14 16:48:57 +0000
committerKaleb Keithley <kaleb@freedesktop.org>2003-11-14 16:48:57 +0000
commit9508a382f8a9f241dab097d921b6d290c1c3a776 (patch)
treefa456480bae7040c3f971a70b390f2d091c680b5 /randr/randr.c
parentded6147bfb5d75ff1e67c858040a628b61bc17d1 (diff)
Initial revision
Diffstat (limited to 'randr/randr.c')
-rw-r--r--randr/randr.c1197
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;
+}