2 * Copyright © 2006 Keith Packard
3 * Copyright © 2008 Red Hat, Inc.
5 * Permission to use, copy, modify, distribute, and sell this software and its
6 * documentation for any purpose is hereby granted without fee, provided that
7 * the above copyright notice appear in all copies and that both that copyright
8 * notice and this permission notice appear in supporting documentation, and
9 * that the name of the copyright holders not be used in advertising or
10 * publicity pertaining to distribution of the software without specific,
11 * written prior permission. The copyright holders make no representations
12 * about the suitability of this software for any purpose. It is provided "as
13 * is" without express or implied warranty.
15 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
17 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
19 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
20 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
29 * Notify the output of some change
32 RROutputChanged(RROutputPtr output
, Bool configChanged
)
34 ScreenPtr pScreen
= output
->pScreen
;
36 output
->changed
= TRUE
;
39 pScrPriv
->changed
= TRUE
;
41 pScrPriv
->configChanged
= TRUE
;
50 RROutputCreate(ScreenPtr pScreen
,
51 const char *name
, int nameLength
, void *devPrivate
)
55 rrScrPrivPtr pScrPriv
;
60 pScrPriv
= rrGetScrPriv(pScreen
);
62 if (pScrPriv
->numOutputs
)
63 outputs
= realloc(pScrPriv
->outputs
,
64 (pScrPriv
->numOutputs
+ 1) * sizeof(RROutputPtr
));
66 outputs
= malloc(sizeof(RROutputPtr
));
70 pScrPriv
->outputs
= outputs
;
72 output
= malloc(sizeof(RROutputRec
) + nameLength
+ 1);
75 output
->id
= FakeClientID(0);
76 output
->pScreen
= pScreen
;
77 output
->name
= (char *) (output
+ 1);
78 output
->nameLength
= nameLength
;
79 memcpy(output
->name
, name
, nameLength
);
80 output
->name
[nameLength
] = '\0';
81 output
->connection
= RR_UnknownConnection
;
82 output
->subpixelOrder
= SubPixelUnknown
;
88 output
->numClones
= 0;
89 output
->clones
= NULL
;
91 output
->numPreferred
= 0;
93 output
->numUserModes
= 0;
94 output
->userModes
= NULL
;
95 output
->properties
= NULL
;
96 output
->pendingProperties
= FALSE
;
97 output
->changed
= FALSE
;
98 output
->devPrivate
= devPrivate
;
100 if (!AddResource(output
->id
, RROutputType
, (pointer
) output
))
103 pScrPriv
->outputs
[pScrPriv
->numOutputs
++] = output
;
108 * Notify extension that output parameters have been changed
111 RROutputSetClones(RROutputPtr output
, RROutputPtr
* clones
, int numClones
)
113 RROutputPtr
*newClones
;
116 if (numClones
== output
->numClones
) {
117 for (i
= 0; i
< numClones
; i
++)
118 if (output
->clones
[i
] != clones
[i
])
124 newClones
= malloc(numClones
* sizeof(RROutputPtr
));
130 free(output
->clones
);
131 memcpy(newClones
, clones
, numClones
* sizeof(RROutputPtr
));
132 output
->clones
= newClones
;
133 output
->numClones
= numClones
;
134 RROutputChanged(output
, TRUE
);
139 RROutputSetModes(RROutputPtr output
,
140 RRModePtr
* modes
, int numModes
, int numPreferred
)
145 if (numModes
== output
->numModes
&& numPreferred
== output
->numPreferred
) {
146 for (i
= 0; i
< numModes
; i
++)
147 if (output
->modes
[i
] != modes
[i
])
150 for (i
= 0; i
< numModes
; i
++)
151 RRModeDestroy(modes
[i
]);
157 newModes
= malloc(numModes
* sizeof(RRModePtr
));
164 for (i
= 0; i
< output
->numModes
; i
++)
165 RRModeDestroy(output
->modes
[i
]);
168 memcpy(newModes
, modes
, numModes
* sizeof(RRModePtr
));
169 output
->modes
= newModes
;
170 output
->numModes
= numModes
;
171 output
->numPreferred
= numPreferred
;
172 RROutputChanged(output
, TRUE
);
177 RROutputAddUserMode(RROutputPtr output
, RRModePtr mode
)
180 ScreenPtr pScreen
= output
->pScreen
;
185 /* Check to see if this mode is already listed for this output */
186 for (m
= 0; m
< output
->numModes
+ output
->numUserModes
; m
++) {
187 RRModePtr e
= (m
< output
->numModes
?
189 output
->userModes
[m
- output
->numModes
]);
194 /* Check with the DDX to see if this mode is OK */
195 if (pScrPriv
->rrOutputValidateMode
)
196 if (!pScrPriv
->rrOutputValidateMode(pScreen
, output
, mode
))
199 if (output
->userModes
)
200 newModes
= realloc(output
->userModes
,
201 (output
->numUserModes
+ 1) * sizeof(RRModePtr
));
203 newModes
= malloc(sizeof(RRModePtr
));
207 output
->userModes
= newModes
;
208 output
->userModes
[output
->numUserModes
++] = mode
;
210 RROutputChanged(output
, TRUE
);
211 RRTellChanged(pScreen
);
216 RROutputDeleteUserMode(RROutputPtr output
, RRModePtr mode
)
220 /* Find this mode in the user mode list */
221 for (m
= 0; m
< output
->numUserModes
; m
++) {
222 RRModePtr e
= output
->userModes
[m
];
227 /* Not there, access error */
228 if (m
== output
->numUserModes
)
231 /* make sure the mode isn't active for this output */
232 if (output
->crtc
&& output
->crtc
->mode
== mode
)
235 memmove(output
->userModes
+ m
, output
->userModes
+ m
+ 1,
236 (output
->numUserModes
- m
- 1) * sizeof(RRModePtr
));
237 output
->numUserModes
--;
243 RROutputSetCrtcs(RROutputPtr output
, RRCrtcPtr
* crtcs
, int numCrtcs
)
248 if (numCrtcs
== output
->numCrtcs
) {
249 for (i
= 0; i
< numCrtcs
; i
++)
250 if (output
->crtcs
[i
] != crtcs
[i
])
256 newCrtcs
= malloc(numCrtcs
* sizeof(RRCrtcPtr
));
263 memcpy(newCrtcs
, crtcs
, numCrtcs
* sizeof(RRCrtcPtr
));
264 output
->crtcs
= newCrtcs
;
265 output
->numCrtcs
= numCrtcs
;
266 RROutputChanged(output
, TRUE
);
271 RROutputSetConnection(RROutputPtr output
, CARD8 connection
)
273 if (output
->connection
== connection
)
275 output
->connection
= connection
;
276 RROutputChanged(output
, TRUE
);
281 RROutputSetSubpixelOrder(RROutputPtr output
, int subpixelOrder
)
283 if (output
->subpixelOrder
== subpixelOrder
)
286 output
->subpixelOrder
= subpixelOrder
;
287 RROutputChanged(output
, FALSE
);
292 RROutputSetPhysicalSize(RROutputPtr output
, int mmWidth
, int mmHeight
)
294 if (output
->mmWidth
== mmWidth
&& output
->mmHeight
== mmHeight
)
296 output
->mmWidth
= mmWidth
;
297 output
->mmHeight
= mmHeight
;
298 RROutputChanged(output
, FALSE
);
303 RRDeliverOutputEvent(ClientPtr client
, WindowPtr pWin
, RROutputPtr output
)
305 ScreenPtr pScreen
= pWin
->drawable
.pScreen
;
308 xRROutputChangeNotifyEvent oe
;
309 RRCrtcPtr crtc
= output
->crtc
;
310 RRModePtr mode
= crtc
? crtc
->mode
: 0;
312 oe
.type
= RRNotify
+ RREventBase
;
313 oe
.subCode
= RRNotify_OutputChange
;
314 oe
.timestamp
= pScrPriv
->lastSetTime
.milliseconds
;
315 oe
.configTimestamp
= pScrPriv
->lastConfigTime
.milliseconds
;
316 oe
.window
= pWin
->drawable
.id
;
317 oe
.output
= output
->id
;
320 oe
.mode
= mode
? mode
->mode
.id
: None
;
321 oe
.rotation
= crtc
->rotation
;
326 oe
.rotation
= RR_Rotate_0
;
328 oe
.connection
= output
->connection
;
329 oe
.subpixelOrder
= output
->subpixelOrder
;
330 WriteEventsToClient(client
, 1, (xEvent
*) &oe
);
334 * Destroy a Output at shutdown
337 RROutputDestroy(RROutputPtr output
)
339 FreeResource(output
->id
, 0);
343 RROutputDestroyResource(pointer value
, XID pid
)
345 RROutputPtr output
= (RROutputPtr
) value
;
346 ScreenPtr pScreen
= output
->pScreen
;
353 if (pScrPriv
->primaryOutput
== output
)
354 pScrPriv
->primaryOutput
= NULL
;
356 for (i
= 0; i
< pScrPriv
->numOutputs
; i
++) {
357 if (pScrPriv
->outputs
[i
] == output
) {
358 memmove(pScrPriv
->outputs
+ i
, pScrPriv
->outputs
+ i
+ 1,
359 (pScrPriv
->numOutputs
- (i
+ 1)) * sizeof(RROutputPtr
));
360 --pScrPriv
->numOutputs
;
366 for (m
= 0; m
< output
->numModes
; m
++)
367 RRModeDestroy(output
->modes
[m
]);
371 for (m
= 0; m
< output
->numUserModes
; m
++)
372 RRModeDestroy(output
->userModes
[m
]);
373 free(output
->userModes
);
376 free(output
->clones
);
377 RRDeleteAllOutputProperties(output
);
383 * Initialize output type
388 RROutputType
= CreateNewResourceType(RROutputDestroyResource
, "OUTPUT");
396 * Initialize output type error value
399 RROutputInitErrorValue(void)
401 SetResourceTypeErrorValue(RROutputType
, RRErrorBase
+ BadRROutput
);
404 #define OutputInfoExtra (SIZEOF(xRRGetOutputInfoReply) - 32)
407 ProcRRGetOutputInfo(ClientPtr client
)
409 REQUEST(xRRGetOutputInfoReq
);
410 xRRGetOutputInfoReply rep
;
413 unsigned long extraLen
;
415 rrScrPrivPtr pScrPriv
;
422 REQUEST_SIZE_MATCH(xRRGetOutputInfoReq
);
423 VERIFY_RR_OUTPUT(stuff
->output
, output
, DixReadAccess
);
425 pScreen
= output
->pScreen
;
426 pScrPriv
= rrGetScrPriv(pScreen
);
429 rep
.sequenceNumber
= client
->sequence
;
430 rep
.length
= bytes_to_int32(OutputInfoExtra
);
431 rep
.timestamp
= pScrPriv
->lastSetTime
.milliseconds
;
432 rep
.crtc
= output
->crtc
? output
->crtc
->id
: None
;
433 rep
.mmWidth
= output
->mmWidth
;
434 rep
.mmHeight
= output
->mmHeight
;
435 rep
.connection
= output
->connection
;
436 rep
.subpixelOrder
= output
->subpixelOrder
;
437 rep
.nCrtcs
= output
->numCrtcs
;
438 rep
.nModes
= output
->numModes
+ output
->numUserModes
;
439 rep
.nPreferred
= output
->numPreferred
;
440 rep
.nClones
= output
->numClones
;
441 rep
.nameLength
= output
->nameLength
;
443 extraLen
= ((output
->numCrtcs
+
444 output
->numModes
+ output
->numUserModes
+
445 output
->numClones
+ bytes_to_int32(rep
.nameLength
)) << 2);
448 rep
.length
+= bytes_to_int32(extraLen
);
449 extra
= malloc(extraLen
);
456 crtcs
= (RRCrtc
*) extra
;
457 modes
= (RRMode
*) (crtcs
+ output
->numCrtcs
);
458 clones
= (RROutput
*) (modes
+ output
->numModes
+ output
->numUserModes
);
459 name
= (char *) (clones
+ output
->numClones
);
461 for (i
= 0; i
< output
->numCrtcs
; i
++) {
462 crtcs
[i
] = output
->crtcs
[i
]->id
;
466 for (i
= 0; i
< output
->numModes
+ output
->numUserModes
; i
++) {
467 if (i
< output
->numModes
)
468 modes
[i
] = output
->modes
[i
]->mode
.id
;
470 modes
[i
] = output
->userModes
[i
- output
->numModes
]->mode
.id
;
474 for (i
= 0; i
< output
->numClones
; i
++) {
475 clones
[i
] = output
->clones
[i
]->id
;
479 memcpy(name
, output
->name
, output
->nameLength
);
480 if (client
->swapped
) {
481 swaps(&rep
.sequenceNumber
);
483 swapl(&rep
.timestamp
);
486 swapl(&rep
.mmHeight
);
490 swaps(&rep
.nameLength
);
492 WriteToClient(client
, sizeof(xRRGetOutputInfoReply
), (char *) &rep
);
494 WriteToClient(client
, extraLen
, (char *) extra
);
502 RRSetPrimaryOutput(ScreenPtr pScreen
, rrScrPrivPtr pScrPriv
, RROutputPtr output
)
504 if (pScrPriv
->primaryOutput
== output
)
507 /* clear the old primary */
508 if (pScrPriv
->primaryOutput
) {
509 RROutputChanged(pScrPriv
->primaryOutput
, 0);
510 pScrPriv
->primaryOutput
= NULL
;
513 /* set the new primary */
515 pScrPriv
->primaryOutput
= output
;
516 RROutputChanged(output
, 0);
519 pScrPriv
->layoutChanged
= TRUE
;
521 RRTellChanged(pScreen
);
525 ProcRRSetOutputPrimary(ClientPtr client
)
527 REQUEST(xRRSetOutputPrimaryReq
);
528 RROutputPtr output
= NULL
;
530 rrScrPrivPtr pScrPriv
;
533 REQUEST_SIZE_MATCH(xRRSetOutputPrimaryReq
);
535 rc
= dixLookupWindow(&pWin
, stuff
->window
, client
, DixGetAttrAccess
);
540 VERIFY_RR_OUTPUT(stuff
->output
, output
, DixReadAccess
);
542 if (output
->pScreen
!= pWin
->drawable
.pScreen
) {
543 client
->errorValue
= stuff
->window
;
548 pScrPriv
= rrGetScrPriv(pWin
->drawable
.pScreen
);
549 RRSetPrimaryOutput(pWin
->drawable
.pScreen
, pScrPriv
, output
);
555 ProcRRGetOutputPrimary(ClientPtr client
)
557 REQUEST(xRRGetOutputPrimaryReq
);
559 rrScrPrivPtr pScrPriv
;
560 xRRGetOutputPrimaryReply rep
;
561 RROutputPtr primary
= NULL
;
564 REQUEST_SIZE_MATCH(xRRGetOutputPrimaryReq
);
566 rc
= dixLookupWindow(&pWin
, stuff
->window
, client
, DixGetAttrAccess
);
570 pScrPriv
= rrGetScrPriv(pWin
->drawable
.pScreen
);
572 primary
= pScrPriv
->primaryOutput
;
574 memset(&rep
, 0, sizeof(rep
));
576 rep
.sequenceNumber
= client
->sequence
;
577 rep
.output
= primary
? primary
->id
: None
;
579 if (client
->swapped
) {
580 swaps(&rep
.sequenceNumber
);
584 WriteToClient(client
, sizeof(xRRGetOutputPrimaryReply
), &rep
);