rroutput.c revision 706f2543
1706f2543Smrg/*
2706f2543Smrg * Copyright © 2006 Keith Packard
3706f2543Smrg * Copyright © 2008 Red Hat, Inc.
4706f2543Smrg *
5706f2543Smrg * Permission to use, copy, modify, distribute, and sell this software and its
6706f2543Smrg * documentation for any purpose is hereby granted without fee, provided that
7706f2543Smrg * the above copyright notice appear in all copies and that both that copyright
8706f2543Smrg * notice and this permission notice appear in supporting documentation, and
9706f2543Smrg * that the name of the copyright holders not be used in advertising or
10706f2543Smrg * publicity pertaining to distribution of the software without specific,
11706f2543Smrg * written prior permission.  The copyright holders make no representations
12706f2543Smrg * about the suitability of this software for any purpose.  It is provided "as
13706f2543Smrg * is" without express or implied warranty.
14706f2543Smrg *
15706f2543Smrg * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16706f2543Smrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
17706f2543Smrg * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18706f2543Smrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
19706f2543Smrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
20706f2543Smrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
21706f2543Smrg * OF THIS SOFTWARE.
22706f2543Smrg */
23706f2543Smrg
24706f2543Smrg#include "randrstr.h"
25706f2543Smrg
26706f2543SmrgRESTYPE	RROutputType;
27706f2543Smrg
28706f2543Smrg/*
29706f2543Smrg * Notify the output of some change
30706f2543Smrg */
31706f2543Smrgvoid
32706f2543SmrgRROutputChanged (RROutputPtr output, Bool configChanged)
33706f2543Smrg{
34706f2543Smrg    ScreenPtr	pScreen = output->pScreen;
35706f2543Smrg
36706f2543Smrg    output->changed = TRUE;
37706f2543Smrg    if (pScreen)
38706f2543Smrg    {
39706f2543Smrg	rrScrPriv (pScreen);
40706f2543Smrg	pScrPriv->changed = TRUE;
41706f2543Smrg	if (configChanged)
42706f2543Smrg	    pScrPriv->configChanged = TRUE;
43706f2543Smrg    }
44706f2543Smrg}
45706f2543Smrg
46706f2543Smrg/*
47706f2543Smrg * Create an output
48706f2543Smrg */
49706f2543Smrg
50706f2543SmrgRROutputPtr
51706f2543SmrgRROutputCreate (ScreenPtr   pScreen,
52706f2543Smrg		const char  *name,
53706f2543Smrg		int	    nameLength,
54706f2543Smrg		void	    *devPrivate)
55706f2543Smrg{
56706f2543Smrg    RROutputPtr	    output;
57706f2543Smrg    RROutputPtr	    *outputs;
58706f2543Smrg    rrScrPrivPtr    pScrPriv;
59706f2543Smrg
60706f2543Smrg    if (!RRInit())
61706f2543Smrg	return NULL;
62706f2543Smrg
63706f2543Smrg    pScrPriv = rrGetScrPriv(pScreen);
64706f2543Smrg
65706f2543Smrg    if (pScrPriv->numOutputs)
66706f2543Smrg	outputs = realloc(pScrPriv->outputs,
67706f2543Smrg			    (pScrPriv->numOutputs + 1) * sizeof (RROutputPtr));
68706f2543Smrg    else
69706f2543Smrg	outputs = malloc(sizeof (RROutputPtr));
70706f2543Smrg    if (!outputs)
71706f2543Smrg	return FALSE;
72706f2543Smrg
73706f2543Smrg    pScrPriv->outputs = outputs;
74706f2543Smrg
75706f2543Smrg    output = malloc(sizeof (RROutputRec) + nameLength + 1);
76706f2543Smrg    if (!output)
77706f2543Smrg	return NULL;
78706f2543Smrg    output->id = FakeClientID (0);
79706f2543Smrg    output->pScreen = pScreen;
80706f2543Smrg    output->name = (char *) (output + 1);
81706f2543Smrg    output->nameLength = nameLength;
82706f2543Smrg    memcpy (output->name, name, nameLength);
83706f2543Smrg    output->name[nameLength] = '\0';
84706f2543Smrg    output->connection = RR_UnknownConnection;
85706f2543Smrg    output->subpixelOrder = SubPixelUnknown;
86706f2543Smrg    output->mmWidth = 0;
87706f2543Smrg    output->mmHeight = 0;
88706f2543Smrg    output->crtc = NULL;
89706f2543Smrg    output->numCrtcs = 0;
90706f2543Smrg    output->crtcs = NULL;
91706f2543Smrg    output->numClones = 0;
92706f2543Smrg    output->clones = NULL;
93706f2543Smrg    output->numModes = 0;
94706f2543Smrg    output->numPreferred = 0;
95706f2543Smrg    output->modes = NULL;
96706f2543Smrg    output->numUserModes = 0;
97706f2543Smrg    output->userModes = NULL;
98706f2543Smrg    output->properties = NULL;
99706f2543Smrg    output->pendingProperties = FALSE;
100706f2543Smrg    output->changed = FALSE;
101706f2543Smrg    output->devPrivate = devPrivate;
102706f2543Smrg
103706f2543Smrg    if (!AddResource (output->id, RROutputType, (pointer) output))
104706f2543Smrg	return NULL;
105706f2543Smrg
106706f2543Smrg    pScrPriv->outputs[pScrPriv->numOutputs++] = output;
107706f2543Smrg    return output;
108706f2543Smrg}
109706f2543Smrg
110706f2543Smrg/*
111706f2543Smrg * Notify extension that output parameters have been changed
112706f2543Smrg */
113706f2543SmrgBool
114706f2543SmrgRROutputSetClones (RROutputPtr  output,
115706f2543Smrg		   RROutputPtr  *clones,
116706f2543Smrg		   int		numClones)
117706f2543Smrg{
118706f2543Smrg    RROutputPtr	*newClones;
119706f2543Smrg    int		i;
120706f2543Smrg
121706f2543Smrg    if (numClones == output->numClones)
122706f2543Smrg    {
123706f2543Smrg	for (i = 0; i < numClones; i++)
124706f2543Smrg	    if (output->clones[i] != clones[i])
125706f2543Smrg		break;
126706f2543Smrg	if (i == numClones)
127706f2543Smrg	    return TRUE;
128706f2543Smrg    }
129706f2543Smrg    if (numClones)
130706f2543Smrg    {
131706f2543Smrg	newClones = malloc(numClones * sizeof (RROutputPtr));
132706f2543Smrg	if (!newClones)
133706f2543Smrg	    return FALSE;
134706f2543Smrg    }
135706f2543Smrg    else
136706f2543Smrg	newClones = NULL;
137706f2543Smrg    free(output->clones);
138706f2543Smrg    memcpy (newClones, clones, numClones * sizeof (RROutputPtr));
139706f2543Smrg    output->clones = newClones;
140706f2543Smrg    output->numClones = numClones;
141706f2543Smrg    RROutputChanged (output, TRUE);
142706f2543Smrg    return TRUE;
143706f2543Smrg}
144706f2543Smrg
145706f2543SmrgBool
146706f2543SmrgRROutputSetModes (RROutputPtr	output,
147706f2543Smrg		  RRModePtr	*modes,
148706f2543Smrg		  int		numModes,
149706f2543Smrg		  int		numPreferred)
150706f2543Smrg{
151706f2543Smrg    RRModePtr	*newModes;
152706f2543Smrg    int		i;
153706f2543Smrg
154706f2543Smrg    if (numModes == output->numModes && numPreferred == output->numPreferred)
155706f2543Smrg    {
156706f2543Smrg	for (i = 0; i < numModes; i++)
157706f2543Smrg	    if (output->modes[i] != modes[i])
158706f2543Smrg		break;
159706f2543Smrg	if (i == numModes)
160706f2543Smrg	{
161706f2543Smrg	    for (i = 0; i < numModes; i++)
162706f2543Smrg		RRModeDestroy (modes[i]);
163706f2543Smrg	    return TRUE;
164706f2543Smrg	}
165706f2543Smrg    }
166706f2543Smrg
167706f2543Smrg    if (numModes)
168706f2543Smrg    {
169706f2543Smrg	newModes = malloc(numModes * sizeof (RRModePtr));
170706f2543Smrg	if (!newModes)
171706f2543Smrg	    return FALSE;
172706f2543Smrg    }
173706f2543Smrg    else
174706f2543Smrg	newModes = NULL;
175706f2543Smrg    if (output->modes)
176706f2543Smrg    {
177706f2543Smrg	for (i = 0; i < output->numModes; i++)
178706f2543Smrg	    RRModeDestroy (output->modes[i]);
179706f2543Smrg	free(output->modes);
180706f2543Smrg    }
181706f2543Smrg    memcpy (newModes, modes, numModes * sizeof (RRModePtr));
182706f2543Smrg    output->modes = newModes;
183706f2543Smrg    output->numModes = numModes;
184706f2543Smrg    output->numPreferred = numPreferred;
185706f2543Smrg    RROutputChanged (output, TRUE);
186706f2543Smrg    return TRUE;
187706f2543Smrg}
188706f2543Smrg
189706f2543Smrgint
190706f2543SmrgRROutputAddUserMode (RROutputPtr    output,
191706f2543Smrg		     RRModePtr	    mode)
192706f2543Smrg{
193706f2543Smrg    int		m;
194706f2543Smrg    ScreenPtr	pScreen = output->pScreen;
195706f2543Smrg    rrScrPriv(pScreen);
196706f2543Smrg    RRModePtr	*newModes;
197706f2543Smrg
198706f2543Smrg    /* Check to see if this mode is already listed for this output */
199706f2543Smrg    for (m = 0; m < output->numModes + output->numUserModes; m++)
200706f2543Smrg    {
201706f2543Smrg	RRModePtr   e = (m < output->numModes ?
202706f2543Smrg			 output->modes[m] :
203706f2543Smrg			 output->userModes[m - output->numModes]);
204706f2543Smrg	if (mode == e)
205706f2543Smrg	    return Success;
206706f2543Smrg    }
207706f2543Smrg
208706f2543Smrg    /* Check with the DDX to see if this mode is OK */
209706f2543Smrg    if (pScrPriv->rrOutputValidateMode)
210706f2543Smrg	if (!pScrPriv->rrOutputValidateMode (pScreen, output, mode))
211706f2543Smrg	    return BadMatch;
212706f2543Smrg
213706f2543Smrg    if (output->userModes)
214706f2543Smrg	newModes = realloc(output->userModes,
215706f2543Smrg			     (output->numUserModes + 1) * sizeof (RRModePtr));
216706f2543Smrg    else
217706f2543Smrg	newModes = malloc(sizeof (RRModePtr));
218706f2543Smrg    if (!newModes)
219706f2543Smrg	return BadAlloc;
220706f2543Smrg
221706f2543Smrg    output->userModes = newModes;
222706f2543Smrg    output->userModes[output->numUserModes++] = mode;
223706f2543Smrg    ++mode->refcnt;
224706f2543Smrg    RROutputChanged (output, TRUE);
225706f2543Smrg    RRTellChanged (pScreen);
226706f2543Smrg    return Success;
227706f2543Smrg}
228706f2543Smrg
229706f2543Smrgint
230706f2543SmrgRROutputDeleteUserMode (RROutputPtr output,
231706f2543Smrg			RRModePtr   mode)
232706f2543Smrg{
233706f2543Smrg    int		m;
234706f2543Smrg
235706f2543Smrg    /* Find this mode in the user mode list */
236706f2543Smrg    for (m = 0; m < output->numUserModes; m++)
237706f2543Smrg    {
238706f2543Smrg	RRModePtr   e = output->userModes[m];
239706f2543Smrg
240706f2543Smrg	if (mode == e)
241706f2543Smrg	    break;
242706f2543Smrg    }
243706f2543Smrg    /* Not there, access error */
244706f2543Smrg    if (m == output->numUserModes)
245706f2543Smrg	return BadAccess;
246706f2543Smrg
247706f2543Smrg    /* make sure the mode isn't active for this output */
248706f2543Smrg    if (output->crtc && output->crtc->mode == mode)
249706f2543Smrg	return BadMatch;
250706f2543Smrg
251706f2543Smrg    memmove (output->userModes + m, output->userModes + m + 1,
252706f2543Smrg	     (output->numUserModes - m - 1) * sizeof (RRModePtr));
253706f2543Smrg    output->numUserModes--;
254706f2543Smrg    RRModeDestroy (mode);
255706f2543Smrg    return Success;
256706f2543Smrg}
257706f2543Smrg
258706f2543SmrgBool
259706f2543SmrgRROutputSetCrtcs (RROutputPtr	output,
260706f2543Smrg		  RRCrtcPtr	*crtcs,
261706f2543Smrg		  int		numCrtcs)
262706f2543Smrg{
263706f2543Smrg    RRCrtcPtr	*newCrtcs;
264706f2543Smrg    int		i;
265706f2543Smrg
266706f2543Smrg    if (numCrtcs == output->numCrtcs)
267706f2543Smrg    {
268706f2543Smrg	for (i = 0; i < numCrtcs; i++)
269706f2543Smrg	    if (output->crtcs[i] != crtcs[i])
270706f2543Smrg		break;
271706f2543Smrg	if (i == numCrtcs)
272706f2543Smrg	    return TRUE;
273706f2543Smrg    }
274706f2543Smrg    if (numCrtcs)
275706f2543Smrg    {
276706f2543Smrg	newCrtcs = malloc(numCrtcs * sizeof (RRCrtcPtr));
277706f2543Smrg	if (!newCrtcs)
278706f2543Smrg	    return FALSE;
279706f2543Smrg    }
280706f2543Smrg    else
281706f2543Smrg	newCrtcs = NULL;
282706f2543Smrg    free(output->crtcs);
283706f2543Smrg    memcpy (newCrtcs, crtcs, numCrtcs * sizeof (RRCrtcPtr));
284706f2543Smrg    output->crtcs = newCrtcs;
285706f2543Smrg    output->numCrtcs = numCrtcs;
286706f2543Smrg    RROutputChanged (output, TRUE);
287706f2543Smrg    return TRUE;
288706f2543Smrg}
289706f2543Smrg
290706f2543SmrgBool
291706f2543SmrgRROutputSetConnection (RROutputPtr  output,
292706f2543Smrg		       CARD8	    connection)
293706f2543Smrg{
294706f2543Smrg    if (output->connection == connection)
295706f2543Smrg	return TRUE;
296706f2543Smrg    output->connection = connection;
297706f2543Smrg    RROutputChanged (output, TRUE);
298706f2543Smrg    return TRUE;
299706f2543Smrg}
300706f2543Smrg
301706f2543SmrgBool
302706f2543SmrgRROutputSetSubpixelOrder (RROutputPtr output,
303706f2543Smrg			  int	      subpixelOrder)
304706f2543Smrg{
305706f2543Smrg    if (output->subpixelOrder == subpixelOrder)
306706f2543Smrg	return TRUE;
307706f2543Smrg
308706f2543Smrg    output->subpixelOrder = subpixelOrder;
309706f2543Smrg    RROutputChanged (output, FALSE);
310706f2543Smrg    return TRUE;
311706f2543Smrg}
312706f2543Smrg
313706f2543SmrgBool
314706f2543SmrgRROutputSetPhysicalSize (RROutputPtr	output,
315706f2543Smrg			 int		mmWidth,
316706f2543Smrg			 int		mmHeight)
317706f2543Smrg{
318706f2543Smrg    if (output->mmWidth == mmWidth && output->mmHeight == mmHeight)
319706f2543Smrg	return TRUE;
320706f2543Smrg    output->mmWidth = mmWidth;
321706f2543Smrg    output->mmHeight = mmHeight;
322706f2543Smrg    RROutputChanged (output, FALSE);
323706f2543Smrg    return TRUE;
324706f2543Smrg}
325706f2543Smrg
326706f2543Smrg
327706f2543Smrgvoid
328706f2543SmrgRRDeliverOutputEvent(ClientPtr client, WindowPtr pWin, RROutputPtr output)
329706f2543Smrg{
330706f2543Smrg    ScreenPtr pScreen = pWin->drawable.pScreen;
331706f2543Smrg    rrScrPriv (pScreen);
332706f2543Smrg    xRROutputChangeNotifyEvent	oe;
333706f2543Smrg    RRCrtcPtr	crtc = output->crtc;
334706f2543Smrg    RRModePtr	mode = crtc ? crtc->mode : 0;
335706f2543Smrg
336706f2543Smrg    oe.type = RRNotify + RREventBase;
337706f2543Smrg    oe.subCode = RRNotify_OutputChange;
338706f2543Smrg    oe.timestamp = pScrPriv->lastSetTime.milliseconds;
339706f2543Smrg    oe.configTimestamp = pScrPriv->lastConfigTime.milliseconds;
340706f2543Smrg    oe.window = pWin->drawable.id;
341706f2543Smrg    oe.output = output->id;
342706f2543Smrg    if (crtc)
343706f2543Smrg    {
344706f2543Smrg	oe.crtc = crtc->id;
345706f2543Smrg	oe.mode = mode ? mode->mode.id : None;
346706f2543Smrg	oe.rotation = crtc->rotation;
347706f2543Smrg    }
348706f2543Smrg    else
349706f2543Smrg    {
350706f2543Smrg	oe.crtc = None;
351706f2543Smrg	oe.mode = None;
352706f2543Smrg	oe.rotation = RR_Rotate_0;
353706f2543Smrg    }
354706f2543Smrg    oe.connection = output->connection;
355706f2543Smrg    oe.subpixelOrder = output->subpixelOrder;
356706f2543Smrg    WriteEventsToClient (client, 1, (xEvent *) &oe);
357706f2543Smrg}
358706f2543Smrg
359706f2543Smrg/*
360706f2543Smrg * Destroy a Output at shutdown
361706f2543Smrg */
362706f2543Smrgvoid
363706f2543SmrgRROutputDestroy (RROutputPtr output)
364706f2543Smrg{
365706f2543Smrg    FreeResource (output->id, 0);
366706f2543Smrg}
367706f2543Smrg
368706f2543Smrgstatic int
369706f2543SmrgRROutputDestroyResource (pointer value, XID pid)
370706f2543Smrg{
371706f2543Smrg    RROutputPtr	output = (RROutputPtr) value;
372706f2543Smrg    ScreenPtr	pScreen = output->pScreen;
373706f2543Smrg    int		m;
374706f2543Smrg
375706f2543Smrg    if (pScreen)
376706f2543Smrg    {
377706f2543Smrg	rrScrPriv(pScreen);
378706f2543Smrg	int		i;
379706f2543Smrg
380706f2543Smrg	if (pScrPriv->primaryOutput == output)
381706f2543Smrg	    pScrPriv->primaryOutput = NULL;
382706f2543Smrg
383706f2543Smrg	for (i = 0; i < pScrPriv->numOutputs; i++)
384706f2543Smrg	{
385706f2543Smrg	    if (pScrPriv->outputs[i] == output)
386706f2543Smrg	    {
387706f2543Smrg		memmove (pScrPriv->outputs + i, pScrPriv->outputs + i + 1,
388706f2543Smrg			 (pScrPriv->numOutputs - (i + 1)) * sizeof (RROutputPtr));
389706f2543Smrg		--pScrPriv->numOutputs;
390706f2543Smrg		break;
391706f2543Smrg	    }
392706f2543Smrg	}
393706f2543Smrg    }
394706f2543Smrg    if (output->modes)
395706f2543Smrg    {
396706f2543Smrg	for (m = 0; m < output->numModes; m++)
397706f2543Smrg	    RRModeDestroy (output->modes[m]);
398706f2543Smrg	free(output->modes);
399706f2543Smrg    }
400706f2543Smrg
401706f2543Smrg    for (m = 0; m < output->numUserModes; m++)
402706f2543Smrg	RRModeDestroy (output->userModes[m]);
403706f2543Smrg    free(output->userModes);
404706f2543Smrg
405706f2543Smrg    free(output->crtcs);
406706f2543Smrg    free(output->clones);
407706f2543Smrg    RRDeleteAllOutputProperties (output);
408706f2543Smrg    free(output);
409706f2543Smrg    return 1;
410706f2543Smrg}
411706f2543Smrg
412706f2543Smrg/*
413706f2543Smrg * Initialize output type
414706f2543Smrg */
415706f2543SmrgBool
416706f2543SmrgRROutputInit (void)
417706f2543Smrg{
418706f2543Smrg    RROutputType = CreateNewResourceType (RROutputDestroyResource, "OUTPUT");
419706f2543Smrg    if (!RROutputType)
420706f2543Smrg	return FALSE;
421706f2543Smrg
422706f2543Smrg    return TRUE;
423706f2543Smrg}
424706f2543Smrg
425706f2543Smrg/*
426706f2543Smrg * Initialize output type error value
427706f2543Smrg */
428706f2543Smrgvoid
429706f2543SmrgRROutputInitErrorValue(void)
430706f2543Smrg{
431706f2543Smrg    SetResourceTypeErrorValue(RROutputType, RRErrorBase + BadRROutput);
432706f2543Smrg}
433706f2543Smrg
434706f2543Smrg#define OutputInfoExtra	(SIZEOF(xRRGetOutputInfoReply) - 32)
435706f2543Smrg
436706f2543Smrgint
437706f2543SmrgProcRRGetOutputInfo (ClientPtr client)
438706f2543Smrg{
439706f2543Smrg    REQUEST(xRRGetOutputInfoReq);
440706f2543Smrg    xRRGetOutputInfoReply	rep;
441706f2543Smrg    RROutputPtr			output;
442706f2543Smrg    CARD8			*extra;
443706f2543Smrg    unsigned long		extraLen;
444706f2543Smrg    ScreenPtr			pScreen;
445706f2543Smrg    rrScrPrivPtr		pScrPriv;
446706f2543Smrg    RRCrtc			*crtcs;
447706f2543Smrg    RRMode			*modes;
448706f2543Smrg    RROutput			*clones;
449706f2543Smrg    char			*name;
450706f2543Smrg    int				i, n;
451706f2543Smrg
452706f2543Smrg    REQUEST_SIZE_MATCH(xRRGetOutputInfoReq);
453706f2543Smrg    VERIFY_RR_OUTPUT(stuff->output, output, DixReadAccess);
454706f2543Smrg
455706f2543Smrg    pScreen = output->pScreen;
456706f2543Smrg    pScrPriv = rrGetScrPriv(pScreen);
457706f2543Smrg
458706f2543Smrg    rep.type = X_Reply;
459706f2543Smrg    rep.sequenceNumber = client->sequence;
460706f2543Smrg    rep.length = bytes_to_int32(OutputInfoExtra);
461706f2543Smrg    rep.timestamp = pScrPriv->lastSetTime.milliseconds;
462706f2543Smrg    rep.crtc = output->crtc ? output->crtc->id : None;
463706f2543Smrg    rep.mmWidth = output->mmWidth;
464706f2543Smrg    rep.mmHeight = output->mmHeight;
465706f2543Smrg    rep.connection = output->connection;
466706f2543Smrg    rep.subpixelOrder = output->subpixelOrder;
467706f2543Smrg    rep.nCrtcs = output->numCrtcs;
468706f2543Smrg    rep.nModes = output->numModes + output->numUserModes;
469706f2543Smrg    rep.nPreferred = output->numPreferred;
470706f2543Smrg    rep.nClones = output->numClones;
471706f2543Smrg    rep.nameLength = output->nameLength;
472706f2543Smrg
473706f2543Smrg    extraLen = ((output->numCrtcs +
474706f2543Smrg		 output->numModes + output->numUserModes +
475706f2543Smrg		 output->numClones +
476706f2543Smrg		 bytes_to_int32(rep.nameLength)) << 2);
477706f2543Smrg
478706f2543Smrg    if (extraLen)
479706f2543Smrg    {
480706f2543Smrg	rep.length += bytes_to_int32(extraLen);
481706f2543Smrg	extra = malloc(extraLen);
482706f2543Smrg	if (!extra)
483706f2543Smrg	    return BadAlloc;
484706f2543Smrg    }
485706f2543Smrg    else
486706f2543Smrg	extra = NULL;
487706f2543Smrg
488706f2543Smrg    crtcs = (RRCrtc *) extra;
489706f2543Smrg    modes = (RRMode *) (crtcs + output->numCrtcs);
490706f2543Smrg    clones = (RROutput *) (modes + output->numModes + output->numUserModes);
491706f2543Smrg    name = (char *) (clones + output->numClones);
492706f2543Smrg
493706f2543Smrg    for (i = 0; i < output->numCrtcs; i++)
494706f2543Smrg    {
495706f2543Smrg	crtcs[i] = output->crtcs[i]->id;
496706f2543Smrg	if (client->swapped)
497706f2543Smrg	    swapl (&crtcs[i], n);
498706f2543Smrg    }
499706f2543Smrg    for (i = 0; i < output->numModes + output->numUserModes; i++)
500706f2543Smrg    {
501706f2543Smrg	if (i < output->numModes)
502706f2543Smrg	    modes[i] = output->modes[i]->mode.id;
503706f2543Smrg	else
504706f2543Smrg	    modes[i] = output->userModes[i - output->numModes]->mode.id;
505706f2543Smrg	if (client->swapped)
506706f2543Smrg	    swapl (&modes[i], n);
507706f2543Smrg    }
508706f2543Smrg    for (i = 0; i < output->numClones; i++)
509706f2543Smrg    {
510706f2543Smrg	clones[i] = output->clones[i]->id;
511706f2543Smrg	if (client->swapped)
512706f2543Smrg	    swapl (&clones[i], n);
513706f2543Smrg    }
514706f2543Smrg    memcpy (name, output->name, output->nameLength);
515706f2543Smrg    if (client->swapped) {
516706f2543Smrg	swaps(&rep.sequenceNumber, n);
517706f2543Smrg	swapl(&rep.length, n);
518706f2543Smrg	swapl(&rep.timestamp, n);
519706f2543Smrg	swapl(&rep.crtc, n);
520706f2543Smrg	swapl(&rep.mmWidth, n);
521706f2543Smrg	swapl(&rep.mmHeight, n);
522706f2543Smrg	swaps(&rep.nCrtcs, n);
523706f2543Smrg	swaps(&rep.nModes, n);
524706f2543Smrg	swaps(&rep.nClones, n);
525706f2543Smrg	swaps(&rep.nameLength, n);
526706f2543Smrg    }
527706f2543Smrg    WriteToClient(client, sizeof(xRRGetOutputInfoReply), (char *)&rep);
528706f2543Smrg    if (extraLen)
529706f2543Smrg    {
530706f2543Smrg	WriteToClient (client, extraLen, (char *) extra);
531706f2543Smrg	free(extra);
532706f2543Smrg    }
533706f2543Smrg
534706f2543Smrg    return Success;
535706f2543Smrg}
536706f2543Smrg
537706f2543Smrgstatic void
538706f2543SmrgRRSetPrimaryOutput(ScreenPtr pScreen, rrScrPrivPtr pScrPriv,
539706f2543Smrg		   RROutputPtr output)
540706f2543Smrg{
541706f2543Smrg    if (pScrPriv->primaryOutput == output)
542706f2543Smrg	return;
543706f2543Smrg
544706f2543Smrg    /* clear the old primary */
545706f2543Smrg    if (pScrPriv->primaryOutput) {
546706f2543Smrg	RROutputChanged(pScrPriv->primaryOutput, 0);
547706f2543Smrg	pScrPriv->primaryOutput = NULL;
548706f2543Smrg    }
549706f2543Smrg
550706f2543Smrg    /* set the new primary */
551706f2543Smrg    if (output) {
552706f2543Smrg	pScrPriv->primaryOutput = output;
553706f2543Smrg	RROutputChanged(output, 0);
554706f2543Smrg    }
555706f2543Smrg
556706f2543Smrg    pScrPriv->layoutChanged = TRUE;
557706f2543Smrg
558706f2543Smrg    RRTellChanged(pScreen);
559706f2543Smrg}
560706f2543Smrg
561706f2543Smrgint
562706f2543SmrgProcRRSetOutputPrimary(ClientPtr client)
563706f2543Smrg{
564706f2543Smrg    REQUEST(xRRSetOutputPrimaryReq);
565706f2543Smrg    RROutputPtr output = NULL;
566706f2543Smrg    WindowPtr pWin;
567706f2543Smrg    rrScrPrivPtr pScrPriv;
568706f2543Smrg    int rc;
569706f2543Smrg
570706f2543Smrg    REQUEST_SIZE_MATCH(xRRSetOutputPrimaryReq);
571706f2543Smrg
572706f2543Smrg    rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
573706f2543Smrg    if (rc != Success)
574706f2543Smrg	return rc;
575706f2543Smrg
576706f2543Smrg    if (stuff->output) {
577706f2543Smrg	VERIFY_RR_OUTPUT(stuff->output, output, DixReadAccess);
578706f2543Smrg
579706f2543Smrg	if (output->pScreen != pWin->drawable.pScreen) {
580706f2543Smrg	    client->errorValue = stuff->window;
581706f2543Smrg	    return BadMatch;
582706f2543Smrg	}
583706f2543Smrg    }
584706f2543Smrg
585706f2543Smrg    pScrPriv = rrGetScrPriv(pWin->drawable.pScreen);
586706f2543Smrg    RRSetPrimaryOutput(pWin->drawable.pScreen, pScrPriv, output);
587706f2543Smrg
588706f2543Smrg    return Success;
589706f2543Smrg}
590706f2543Smrg
591706f2543Smrgint
592706f2543SmrgProcRRGetOutputPrimary(ClientPtr client)
593706f2543Smrg{
594706f2543Smrg    REQUEST(xRRGetOutputPrimaryReq);
595706f2543Smrg    WindowPtr pWin;
596706f2543Smrg    rrScrPrivPtr pScrPriv;
597706f2543Smrg    xRRGetOutputPrimaryReply rep;
598706f2543Smrg    RROutputPtr primary = NULL;
599706f2543Smrg    int rc;
600706f2543Smrg
601706f2543Smrg    REQUEST_SIZE_MATCH(xRRGetOutputPrimaryReq);
602706f2543Smrg
603706f2543Smrg    rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
604706f2543Smrg    if (rc != Success)
605706f2543Smrg	return rc;
606706f2543Smrg
607706f2543Smrg    pScrPriv = rrGetScrPriv(pWin->drawable.pScreen);
608706f2543Smrg    if (pScrPriv)
609706f2543Smrg	primary = pScrPriv->primaryOutput;
610706f2543Smrg
611706f2543Smrg    memset(&rep, 0, sizeof(rep));
612706f2543Smrg    rep.type = X_Reply;
613706f2543Smrg    rep.sequenceNumber = client->sequence;
614706f2543Smrg    rep.output = primary ? primary->id : None;
615706f2543Smrg
616706f2543Smrg    if (client->swapped) {
617706f2543Smrg	int n;
618706f2543Smrg	swaps(&rep.sequenceNumber, n);
619706f2543Smrg	swapl(&rep.output, n);
620706f2543Smrg    }
621706f2543Smrg
622706f2543Smrg    WriteToClient(client, sizeof(xRRGetOutputPrimaryReply), &rep);
623706f2543Smrg
624706f2543Smrg    return Success;
625706f2543Smrg}
626