1706f2543Smrg/*
2706f2543Smrg * Copyright © 2000 Compaq Computer Corporation
3706f2543Smrg * Copyright © 2002 Hewlett-Packard Company
4706f2543Smrg * Copyright © 2006 Intel Corporation
5706f2543Smrg *
6706f2543Smrg * Permission to use, copy, modify, distribute, and sell this software and its
7706f2543Smrg * documentation for any purpose is hereby granted without fee, provided that
8706f2543Smrg * the above copyright notice appear in all copies and that both that copyright
9706f2543Smrg * notice and this permission notice appear in supporting documentation, and
10706f2543Smrg * that the name of the copyright holders not be used in advertising or
11706f2543Smrg * publicity pertaining to distribution of the software without specific,
12706f2543Smrg * written prior permission.  The copyright holders make no representations
13706f2543Smrg * about the suitability of this software for any purpose.  It is provided "as
14706f2543Smrg * is" without express or implied warranty.
15706f2543Smrg *
16706f2543Smrg * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17706f2543Smrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18706f2543Smrg * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19706f2543Smrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
20706f2543Smrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
21706f2543Smrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
22706f2543Smrg * OF THIS SOFTWARE.
23706f2543Smrg *
24706f2543Smrg * Author:  Jim Gettys, Hewlett-Packard Company, Inc.
25706f2543Smrg *	    Keith Packard, Intel Corporation
26706f2543Smrg */
27706f2543Smrg
28706f2543Smrg#ifdef HAVE_DIX_CONFIG_H
29706f2543Smrg#include <dix-config.h>
30706f2543Smrg#endif
31706f2543Smrg
32706f2543Smrg#include "randrstr.h"
33706f2543Smrg
34706f2543Smrg/* From render.h */
35706f2543Smrg#ifndef SubPixelUnknown
36706f2543Smrg#define SubPixelUnknown 0
37706f2543Smrg#endif
38706f2543Smrg
39706f2543Smrg#define RR_VALIDATE
40706f2543Smrgstatic int	RRNScreens;
41706f2543Smrg
42706f2543Smrg#define wrap(priv,real,mem,func) {\
43706f2543Smrg    priv->mem = real->mem; \
44706f2543Smrg    real->mem = func; \
45706f2543Smrg}
46706f2543Smrg
47706f2543Smrg#define unwrap(priv,real,mem) {\
48706f2543Smrg    real->mem = priv->mem; \
49706f2543Smrg}
50706f2543Smrg
51706f2543Smrgstatic int ProcRRDispatch (ClientPtr pClient);
52706f2543Smrgstatic int SProcRRDispatch (ClientPtr pClient);
53706f2543Smrg
54706f2543Smrgint	RREventBase;
55706f2543Smrgint	RRErrorBase;
56706f2543SmrgRESTYPE RRClientType, RREventType; /* resource types for event masks */
57706f2543SmrgDevPrivateKeyRec RRClientPrivateKeyRec;
58706f2543Smrg
59706f2543SmrgDevPrivateKeyRec rrPrivKeyRec;
60706f2543Smrg
61706f2543Smrgstatic void
62706f2543SmrgRRClientCallback (CallbackListPtr	*list,
63706f2543Smrg		  pointer		closure,
64706f2543Smrg		  pointer		data)
65706f2543Smrg{
66706f2543Smrg    NewClientInfoRec	*clientinfo = (NewClientInfoRec *) data;
67706f2543Smrg    ClientPtr		pClient = clientinfo->client;
68706f2543Smrg    rrClientPriv(pClient);
69706f2543Smrg    RRTimesPtr		pTimes = (RRTimesPtr) (pRRClient + 1);
70706f2543Smrg    int			i;
71706f2543Smrg
72706f2543Smrg    pRRClient->major_version = 0;
73706f2543Smrg    pRRClient->minor_version = 0;
74706f2543Smrg    for (i = 0; i < screenInfo.numScreens; i++)
75706f2543Smrg    {
76706f2543Smrg	ScreenPtr   pScreen = screenInfo.screens[i];
77706f2543Smrg	rrScrPriv(pScreen);
78706f2543Smrg
79706f2543Smrg	if (pScrPriv)
80706f2543Smrg	{
81706f2543Smrg	    pTimes[i].setTime = pScrPriv->lastSetTime;
82706f2543Smrg	    pTimes[i].configTime = pScrPriv->lastConfigTime;
83706f2543Smrg	}
84706f2543Smrg    }
85706f2543Smrg}
86706f2543Smrg
87706f2543Smrgstatic Bool
88706f2543SmrgRRCloseScreen (int i, ScreenPtr pScreen)
89706f2543Smrg{
90706f2543Smrg    rrScrPriv(pScreen);
91706f2543Smrg    int		    j;
92706f2543Smrg
93706f2543Smrg    unwrap (pScrPriv, pScreen, CloseScreen);
94706f2543Smrg    for (j = pScrPriv->numCrtcs - 1; j >= 0; j--)
95706f2543Smrg	RRCrtcDestroy (pScrPriv->crtcs[j]);
96706f2543Smrg    for (j = pScrPriv->numOutputs - 1; j >= 0; j--)
97706f2543Smrg	RROutputDestroy (pScrPriv->outputs[j]);
98706f2543Smrg
99706f2543Smrg    free(pScrPriv->crtcs);
100706f2543Smrg    free(pScrPriv->outputs);
101706f2543Smrg    free(pScrPriv);
102706f2543Smrg    RRNScreens -= 1;	/* ok, one fewer screen with RandR running */
103706f2543Smrg    return (*pScreen->CloseScreen) (i, pScreen);
104706f2543Smrg}
105706f2543Smrg
106706f2543Smrgstatic void
107706f2543SmrgSRRScreenChangeNotifyEvent(xRRScreenChangeNotifyEvent *from,
108706f2543Smrg			   xRRScreenChangeNotifyEvent *to)
109706f2543Smrg{
110706f2543Smrg    to->type = from->type;
111706f2543Smrg    to->rotation = from->rotation;
112706f2543Smrg    cpswaps(from->sequenceNumber, to->sequenceNumber);
113706f2543Smrg    cpswapl(from->timestamp, to->timestamp);
114706f2543Smrg    cpswapl(from->configTimestamp, to->configTimestamp);
115706f2543Smrg    cpswapl(from->root, to->root);
116706f2543Smrg    cpswapl(from->window, to->window);
117706f2543Smrg    cpswaps(from->sizeID, to->sizeID);
118706f2543Smrg    cpswaps(from->subpixelOrder, to->subpixelOrder);
119706f2543Smrg    cpswaps(from->widthInPixels, to->widthInPixels);
120706f2543Smrg    cpswaps(from->heightInPixels, to->heightInPixels);
121706f2543Smrg    cpswaps(from->widthInMillimeters, to->widthInMillimeters);
122706f2543Smrg    cpswaps(from->heightInMillimeters, to->heightInMillimeters);
123706f2543Smrg}
124706f2543Smrg
125706f2543Smrgstatic void
126706f2543SmrgSRRCrtcChangeNotifyEvent(xRRCrtcChangeNotifyEvent *from,
127706f2543Smrg			 xRRCrtcChangeNotifyEvent *to)
128706f2543Smrg{
129706f2543Smrg    to->type = from->type;
130706f2543Smrg    to->subCode = from->subCode;
131706f2543Smrg    cpswaps(from->sequenceNumber, to->sequenceNumber);
132706f2543Smrg    cpswapl(from->timestamp, to->timestamp);
133706f2543Smrg    cpswapl(from->window, to->window);
134706f2543Smrg    cpswapl(from->crtc, to->crtc);
135706f2543Smrg    cpswapl(from->mode, to->mode);
136706f2543Smrg    cpswaps(from->rotation, to->rotation);
137706f2543Smrg    /* pad1 */
138706f2543Smrg    cpswaps(from->x, to->x);
139706f2543Smrg    cpswaps(from->y, to->y);
140706f2543Smrg    cpswaps(from->width, to->width);
141706f2543Smrg    cpswaps(from->height, to->height);
142706f2543Smrg}
143706f2543Smrg
144706f2543Smrgstatic void
145706f2543SmrgSRROutputChangeNotifyEvent(xRROutputChangeNotifyEvent *from,
146706f2543Smrg			   xRROutputChangeNotifyEvent *to)
147706f2543Smrg{
148706f2543Smrg    to->type = from->type;
149706f2543Smrg    to->subCode = from->subCode;
150706f2543Smrg    cpswaps(from->sequenceNumber, to->sequenceNumber);
151706f2543Smrg    cpswapl(from->timestamp, to->timestamp);
152706f2543Smrg    cpswapl(from->configTimestamp, to->configTimestamp);
153706f2543Smrg    cpswapl(from->window, to->window);
154706f2543Smrg    cpswapl(from->output, to->output);
155706f2543Smrg    cpswapl(from->crtc, to->crtc);
156706f2543Smrg    cpswapl(from->mode, to->mode);
157706f2543Smrg    cpswaps(from->rotation, to->rotation);
158706f2543Smrg    to->connection = from->connection;
159706f2543Smrg    to->subpixelOrder = from->subpixelOrder;
160706f2543Smrg}
161706f2543Smrg
162706f2543Smrgstatic void
163706f2543SmrgSRROutputPropertyNotifyEvent(xRROutputPropertyNotifyEvent *from,
164706f2543Smrg			     xRROutputPropertyNotifyEvent *to)
165706f2543Smrg{
166706f2543Smrg    to->type = from->type;
167706f2543Smrg    to->subCode = from->subCode;
168706f2543Smrg    cpswaps(from->sequenceNumber, to->sequenceNumber);
169706f2543Smrg    cpswapl(from->window, to->window);
170706f2543Smrg    cpswapl(from->output, to->output);
171706f2543Smrg    cpswapl(from->atom, to->atom);
172706f2543Smrg    cpswapl(from->timestamp, to->timestamp);
173706f2543Smrg    to->state = from->state;
174706f2543Smrg    /* pad1 */
175706f2543Smrg    /* pad2 */
176706f2543Smrg    /* pad3 */
177706f2543Smrg    /* pad4 */
178706f2543Smrg}
179706f2543Smrg
180706f2543Smrgstatic void
181706f2543SmrgSRRNotifyEvent (xEvent *from,
182706f2543Smrg		xEvent *to)
183706f2543Smrg{
184706f2543Smrg    switch (from->u.u.detail) {
185706f2543Smrg    case RRNotify_CrtcChange:
186706f2543Smrg	SRRCrtcChangeNotifyEvent ((xRRCrtcChangeNotifyEvent *) from,
187706f2543Smrg				  (xRRCrtcChangeNotifyEvent *) to);
188706f2543Smrg	break;
189706f2543Smrg    case RRNotify_OutputChange:
190706f2543Smrg	SRROutputChangeNotifyEvent ((xRROutputChangeNotifyEvent *) from,
191706f2543Smrg				    (xRROutputChangeNotifyEvent *) to);
192706f2543Smrg	break;
193706f2543Smrg    case RRNotify_OutputProperty:
194706f2543Smrg	SRROutputPropertyNotifyEvent ((xRROutputPropertyNotifyEvent *) from,
195706f2543Smrg				      (xRROutputPropertyNotifyEvent *) to);
196706f2543Smrg	break;
197706f2543Smrg    default:
198706f2543Smrg	break;
199706f2543Smrg    }
200706f2543Smrg}
201706f2543Smrg
202706f2543Smrgstatic int RRGeneration;
203706f2543Smrg
204706f2543SmrgBool RRInit (void)
205706f2543Smrg{
206706f2543Smrg    if (RRGeneration != serverGeneration)
207706f2543Smrg    {
208706f2543Smrg	if (!RRModeInit ())
209706f2543Smrg	    return FALSE;
210706f2543Smrg	if (!RRCrtcInit ())
211706f2543Smrg	    return FALSE;
212706f2543Smrg	if (!RROutputInit ())
213706f2543Smrg	    return FALSE;
214706f2543Smrg	RRGeneration = serverGeneration;
215706f2543Smrg    }
216706f2543Smrg    if (!dixRegisterPrivateKey(&rrPrivKeyRec, PRIVATE_SCREEN, 0))
217706f2543Smrg	return FALSE;
218706f2543Smrg
219706f2543Smrg    return TRUE;
220706f2543Smrg}
221706f2543Smrg
222706f2543SmrgBool RRScreenInit(ScreenPtr pScreen)
223706f2543Smrg{
224706f2543Smrg    rrScrPrivPtr   pScrPriv;
225706f2543Smrg
226706f2543Smrg    if (!RRInit ())
227706f2543Smrg	return FALSE;
228706f2543Smrg
229706f2543Smrg    pScrPriv = (rrScrPrivPtr) calloc(1, sizeof (rrScrPrivRec));
230706f2543Smrg    if (!pScrPriv)
231706f2543Smrg	return FALSE;
232706f2543Smrg
233706f2543Smrg    SetRRScreen(pScreen, pScrPriv);
234706f2543Smrg
235706f2543Smrg    /*
236706f2543Smrg     * Calling function best set these function vectors
237706f2543Smrg     */
238706f2543Smrg    pScrPriv->rrGetInfo = 0;
239706f2543Smrg    pScrPriv->maxWidth = pScrPriv->minWidth = pScreen->width;
240706f2543Smrg    pScrPriv->maxHeight = pScrPriv->minHeight = pScreen->height;
241706f2543Smrg
242706f2543Smrg    pScrPriv->width = pScreen->width;
243706f2543Smrg    pScrPriv->height = pScreen->height;
244706f2543Smrg    pScrPriv->mmWidth = pScreen->mmWidth;
245706f2543Smrg    pScrPriv->mmHeight = pScreen->mmHeight;
246706f2543Smrg#if RANDR_12_INTERFACE
247706f2543Smrg    pScrPriv->rrScreenSetSize = NULL;
248706f2543Smrg    pScrPriv->rrCrtcSet = NULL;
249706f2543Smrg    pScrPriv->rrCrtcSetGamma = NULL;
250706f2543Smrg#endif
251706f2543Smrg#if RANDR_10_INTERFACE
252706f2543Smrg    pScrPriv->rrSetConfig = 0;
253706f2543Smrg    pScrPriv->rotations = RR_Rotate_0;
254706f2543Smrg    pScrPriv->reqWidth = pScreen->width;
255706f2543Smrg    pScrPriv->reqHeight = pScreen->height;
256706f2543Smrg    pScrPriv->nSizes = 0;
257706f2543Smrg    pScrPriv->pSizes = NULL;
258706f2543Smrg    pScrPriv->rotation = RR_Rotate_0;
259706f2543Smrg    pScrPriv->rate = 0;
260706f2543Smrg    pScrPriv->size = 0;
261706f2543Smrg#endif
262706f2543Smrg
263706f2543Smrg    /*
264706f2543Smrg     * This value doesn't really matter -- any client must call
265706f2543Smrg     * GetScreenInfo before reading it which will automatically update
266706f2543Smrg     * the time
267706f2543Smrg     */
268706f2543Smrg    pScrPriv->lastSetTime = currentTime;
269706f2543Smrg    pScrPriv->lastConfigTime = currentTime;
270706f2543Smrg
271706f2543Smrg    wrap (pScrPriv, pScreen, CloseScreen, RRCloseScreen);
272706f2543Smrg
273706f2543Smrg    pScrPriv->numOutputs = 0;
274706f2543Smrg    pScrPriv->outputs = NULL;
275706f2543Smrg    pScrPriv->numCrtcs = 0;
276706f2543Smrg    pScrPriv->crtcs = NULL;
277706f2543Smrg
278706f2543Smrg    RRNScreens += 1;	/* keep count of screens that implement randr */
279706f2543Smrg    return TRUE;
280706f2543Smrg}
281706f2543Smrg
282706f2543Smrg/*ARGSUSED*/
283706f2543Smrgstatic int
284706f2543SmrgRRFreeClient (pointer data, XID id)
285706f2543Smrg{
286706f2543Smrg    RREventPtr   pRREvent;
287706f2543Smrg    WindowPtr	    pWin;
288706f2543Smrg    RREventPtr   *pHead, pCur, pPrev;
289706f2543Smrg
290706f2543Smrg    pRREvent = (RREventPtr) data;
291706f2543Smrg    pWin = pRREvent->window;
292706f2543Smrg    dixLookupResourceByType((pointer *)&pHead, pWin->drawable.id,
293706f2543Smrg			    RREventType, serverClient, DixDestroyAccess);
294706f2543Smrg    if (pHead) {
295706f2543Smrg	pPrev = 0;
296706f2543Smrg	for (pCur = *pHead; pCur && pCur != pRREvent; pCur=pCur->next)
297706f2543Smrg	    pPrev = pCur;
298706f2543Smrg	if (pCur)
299706f2543Smrg	{
300706f2543Smrg	    if (pPrev)
301706f2543Smrg	    	pPrev->next = pRREvent->next;
302706f2543Smrg	    else
303706f2543Smrg	    	*pHead = pRREvent->next;
304706f2543Smrg	}
305706f2543Smrg    }
306706f2543Smrg    free((pointer) pRREvent);
307706f2543Smrg    return 1;
308706f2543Smrg}
309706f2543Smrg
310706f2543Smrg/*ARGSUSED*/
311706f2543Smrgstatic int
312706f2543SmrgRRFreeEvents (pointer data, XID id)
313706f2543Smrg{
314706f2543Smrg    RREventPtr   *pHead, pCur, pNext;
315706f2543Smrg
316706f2543Smrg    pHead = (RREventPtr *) data;
317706f2543Smrg    for (pCur = *pHead; pCur; pCur = pNext) {
318706f2543Smrg	pNext = pCur->next;
319706f2543Smrg	FreeResource (pCur->clientResource, RRClientType);
320706f2543Smrg	free((pointer) pCur);
321706f2543Smrg    }
322706f2543Smrg    free((pointer) pHead);
323706f2543Smrg    return 1;
324706f2543Smrg}
325706f2543Smrg
326706f2543Smrgvoid
327706f2543SmrgRRExtensionInit (void)
328706f2543Smrg{
329706f2543Smrg    ExtensionEntry *extEntry;
330706f2543Smrg
331706f2543Smrg    if (RRNScreens == 0) return;
332706f2543Smrg
333706f2543Smrg    if (!dixRegisterPrivateKey(&RRClientPrivateKeyRec, PRIVATE_CLIENT,
334706f2543Smrg			       sizeof (RRClientRec) +
335706f2543Smrg			       screenInfo.numScreens * sizeof (RRTimesRec)))
336706f2543Smrg	return;
337706f2543Smrg    if (!AddCallback (&ClientStateCallback, RRClientCallback, 0))
338706f2543Smrg	return;
339706f2543Smrg
340706f2543Smrg    RRClientType = CreateNewResourceType(RRFreeClient, "RandRClient");
341706f2543Smrg    if (!RRClientType)
342706f2543Smrg	return;
343706f2543Smrg    RREventType = CreateNewResourceType(RRFreeEvents, "RandREvent");
344706f2543Smrg    if (!RREventType)
345706f2543Smrg	return;
346706f2543Smrg    extEntry = AddExtension (RANDR_NAME, RRNumberEvents, RRNumberErrors,
347706f2543Smrg			     ProcRRDispatch, SProcRRDispatch,
348706f2543Smrg			     NULL, StandardMinorOpcode);
349706f2543Smrg    if (!extEntry)
350706f2543Smrg	return;
351706f2543Smrg    RRErrorBase = extEntry->errorBase;
352706f2543Smrg    RREventBase = extEntry->eventBase;
353706f2543Smrg    EventSwapVector[RREventBase + RRScreenChangeNotify] = (EventSwapPtr)
354706f2543Smrg	SRRScreenChangeNotifyEvent;
355706f2543Smrg    EventSwapVector[RREventBase + RRNotify] = (EventSwapPtr)
356706f2543Smrg	SRRNotifyEvent;
357706f2543Smrg
358706f2543Smrg    RRModeInitErrorValue();
359706f2543Smrg    RRCrtcInitErrorValue();
360706f2543Smrg    RROutputInitErrorValue();
361706f2543Smrg
362706f2543Smrg#ifdef PANORAMIX
363706f2543Smrg    RRXineramaExtensionInit();
364706f2543Smrg#endif
365706f2543Smrg}
366706f2543Smrg
367706f2543Smrgstatic int
368706f2543SmrgTellChanged (WindowPtr pWin, pointer value)
369706f2543Smrg{
370706f2543Smrg    RREventPtr			*pHead, pRREvent;
371706f2543Smrg    ClientPtr			client;
372706f2543Smrg    ScreenPtr			pScreen = pWin->drawable.pScreen;
373706f2543Smrg    rrScrPriv(pScreen);
374706f2543Smrg    int				i;
375706f2543Smrg
376706f2543Smrg    dixLookupResourceByType((pointer *)&pHead, pWin->drawable.id,
377706f2543Smrg			    RREventType, serverClient, DixReadAccess);
378706f2543Smrg    if (!pHead)
379706f2543Smrg	return WT_WALKCHILDREN;
380706f2543Smrg
381706f2543Smrg    for (pRREvent = *pHead; pRREvent; pRREvent = pRREvent->next)
382706f2543Smrg    {
383706f2543Smrg	client = pRREvent->client;
384706f2543Smrg	if (client == serverClient || client->clientGone)
385706f2543Smrg	    continue;
386706f2543Smrg
387706f2543Smrg	if (pRREvent->mask & RRScreenChangeNotifyMask)
388706f2543Smrg	    RRDeliverScreenEvent (client, pWin, pScreen);
389706f2543Smrg
390706f2543Smrg	if (pRREvent->mask & RRCrtcChangeNotifyMask)
391706f2543Smrg	{
392706f2543Smrg	    for (i = 0; i < pScrPriv->numCrtcs; i++)
393706f2543Smrg	    {
394706f2543Smrg		RRCrtcPtr   crtc = pScrPriv->crtcs[i];
395706f2543Smrg		if (crtc->changed)
396706f2543Smrg		    RRDeliverCrtcEvent (client, pWin, crtc);
397706f2543Smrg	    }
398706f2543Smrg	}
399706f2543Smrg
400706f2543Smrg	if (pRREvent->mask & RROutputChangeNotifyMask)
401706f2543Smrg	{
402706f2543Smrg	    for (i = 0; i < pScrPriv->numOutputs; i++)
403706f2543Smrg	    {
404706f2543Smrg		RROutputPtr   output = pScrPriv->outputs[i];
405706f2543Smrg		if (output->changed)
406706f2543Smrg		    RRDeliverOutputEvent (client, pWin, output);
407706f2543Smrg	    }
408706f2543Smrg	}
409706f2543Smrg    }
410706f2543Smrg    return WT_WALKCHILDREN;
411706f2543Smrg}
412706f2543Smrg
413706f2543Smrg/*
414706f2543Smrg * Something changed; send events and adjust pointer position
415706f2543Smrg */
416706f2543Smrgvoid
417706f2543SmrgRRTellChanged (ScreenPtr pScreen)
418706f2543Smrg{
419706f2543Smrg    rrScrPriv (pScreen);
420706f2543Smrg    int i;
421706f2543Smrg
422706f2543Smrg    if (pScrPriv->changed)
423706f2543Smrg    {
424706f2543Smrg	UpdateCurrentTime ();
425706f2543Smrg	if (pScrPriv->configChanged)
426706f2543Smrg	{
427706f2543Smrg	    pScrPriv->lastConfigTime = currentTime;
428706f2543Smrg	    pScrPriv->configChanged = FALSE;
429706f2543Smrg	}
430706f2543Smrg	pScrPriv->changed = FALSE;
431706f2543Smrg	WalkTree (pScreen, TellChanged, (pointer) pScreen);
432706f2543Smrg	for (i = 0; i < pScrPriv->numOutputs; i++)
433706f2543Smrg	    pScrPriv->outputs[i]->changed = FALSE;
434706f2543Smrg	for (i = 0; i < pScrPriv->numCrtcs; i++)
435706f2543Smrg	    pScrPriv->crtcs[i]->changed = FALSE;
436706f2543Smrg	if (pScrPriv->layoutChanged)
437706f2543Smrg	{
438706f2543Smrg	    pScrPriv->layoutChanged = FALSE;
439706f2543Smrg	    RRPointerScreenConfigured (pScreen);
440706f2543Smrg	    RRSendConfigNotify (pScreen);
441706f2543Smrg	}
442706f2543Smrg    }
443706f2543Smrg}
444706f2543Smrg
445706f2543Smrgvoid
446706f2543SmrgRRSetChanged(ScreenPtr pScreen)
447706f2543Smrg{
448706f2543Smrg	rrScrPriv(pScreen);
449706f2543Smrg
450706f2543Smrg	pScrPriv->changed = TRUE;
451706f2543Smrg}
452706f2543Smrg
453706f2543Smrg/*
454706f2543Smrg * Return the first output which is connected to an active CRTC
455706f2543Smrg * Used in emulating 1.0 behaviour
456706f2543Smrg */
457706f2543SmrgRROutputPtr
458706f2543SmrgRRFirstOutput (ScreenPtr pScreen)
459706f2543Smrg{
460706f2543Smrg    rrScrPriv(pScreen);
461706f2543Smrg    RROutputPtr		    output;
462706f2543Smrg    int	i, j;
463706f2543Smrg
464706f2543Smrg    if (pScrPriv->primaryOutput && pScrPriv->primaryOutput->crtc)
465706f2543Smrg	return pScrPriv->primaryOutput;
466706f2543Smrg
467706f2543Smrg    for (i = 0; i < pScrPriv->numCrtcs; i++)
468706f2543Smrg    {
469706f2543Smrg	RRCrtcPtr   crtc = pScrPriv->crtcs[i];
470706f2543Smrg	for (j = 0; j < pScrPriv->numOutputs; j++)
471706f2543Smrg	{
472706f2543Smrg	    output = pScrPriv->outputs[j];
473706f2543Smrg	    if (output->crtc == crtc)
474706f2543Smrg		return output;
475706f2543Smrg	}
476706f2543Smrg    }
477706f2543Smrg    return NULL;
478706f2543Smrg}
479706f2543Smrg
480706f2543SmrgCARD16
481706f2543SmrgRRVerticalRefresh (xRRModeInfo *mode)
482706f2543Smrg{
483706f2543Smrg    CARD32  refresh;
484706f2543Smrg    CARD32  dots = mode->hTotal * mode->vTotal;
485706f2543Smrg    if (!dots)
486706f2543Smrg	return 0;
487706f2543Smrg    refresh = (mode->dotClock + dots/2) / dots;
488706f2543Smrg    if (refresh > 0xffff)
489706f2543Smrg	refresh = 0xffff;
490706f2543Smrg    return (CARD16) refresh;
491706f2543Smrg}
492706f2543Smrg
493706f2543Smrgstatic int
494706f2543SmrgProcRRDispatch (ClientPtr client)
495706f2543Smrg{
496706f2543Smrg    REQUEST(xReq);
497706f2543Smrg    if (stuff->data >= RRNumberRequests || !ProcRandrVector[stuff->data])
498706f2543Smrg	return BadRequest;
499706f2543Smrg    return (*ProcRandrVector[stuff->data]) (client);
500706f2543Smrg}
501706f2543Smrg
502706f2543Smrgstatic int
503706f2543SmrgSProcRRDispatch (ClientPtr client)
504706f2543Smrg{
505706f2543Smrg    REQUEST(xReq);
506706f2543Smrg    if (stuff->data >= RRNumberRequests || !ProcRandrVector[stuff->data])
507706f2543Smrg	return BadRequest;
508706f2543Smrg    return (*SProcRandrVector[stuff->data]) (client);
509706f2543Smrg}
510706f2543Smrg
511