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 RRSetChanged(pScreen
);
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
;
105 RRResourcesChanged(pScreen
);
111 * Notify extension that output parameters have been changed
114 RROutputSetClones(RROutputPtr output
, RROutputPtr
* clones
, int numClones
)
116 RROutputPtr
*newClones
;
119 if (numClones
== output
->numClones
) {
120 for (i
= 0; i
< numClones
; i
++)
121 if (output
->clones
[i
] != clones
[i
])
127 newClones
= malloc(numClones
* sizeof(RROutputPtr
));
133 free(output
->clones
);
134 memcpy(newClones
, clones
, numClones
* sizeof(RROutputPtr
));
135 output
->clones
= newClones
;
136 output
->numClones
= numClones
;
137 RROutputChanged(output
, TRUE
);
142 RROutputSetModes(RROutputPtr output
,
143 RRModePtr
* modes
, int numModes
, int numPreferred
)
148 if (numModes
== output
->numModes
&& numPreferred
== output
->numPreferred
) {
149 for (i
= 0; i
< numModes
; i
++)
150 if (output
->modes
[i
] != modes
[i
])
153 for (i
= 0; i
< numModes
; i
++)
154 RRModeDestroy(modes
[i
]);
160 newModes
= malloc(numModes
* sizeof(RRModePtr
));
167 for (i
= 0; i
< output
->numModes
; i
++)
168 RRModeDestroy(output
->modes
[i
]);
171 memcpy(newModes
, modes
, numModes
* sizeof(RRModePtr
));
172 output
->modes
= newModes
;
173 output
->numModes
= numModes
;
174 output
->numPreferred
= numPreferred
;
175 RROutputChanged(output
, TRUE
);
180 RROutputAddUserMode(RROutputPtr output
, RRModePtr mode
)
183 ScreenPtr pScreen
= output
->pScreen
;
188 /* Check to see if this mode is already listed for this output */
189 for (m
= 0; m
< output
->numModes
+ output
->numUserModes
; m
++) {
190 RRModePtr e
= (m
< output
->numModes
?
192 output
->userModes
[m
- output
->numModes
]);
197 /* Check with the DDX to see if this mode is OK */
198 if (pScrPriv
->rrOutputValidateMode
)
199 if (!pScrPriv
->rrOutputValidateMode(pScreen
, output
, mode
))
202 if (output
->userModes
)
203 newModes
= realloc(output
->userModes
,
204 (output
->numUserModes
+ 1) * sizeof(RRModePtr
));
206 newModes
= malloc(sizeof(RRModePtr
));
210 output
->userModes
= newModes
;
211 output
->userModes
[output
->numUserModes
++] = mode
;
213 RROutputChanged(output
, TRUE
);
214 RRTellChanged(pScreen
);
219 RROutputDeleteUserMode(RROutputPtr output
, RRModePtr mode
)
223 /* Find this mode in the user mode list */
224 for (m
= 0; m
< output
->numUserModes
; m
++) {
225 RRModePtr e
= output
->userModes
[m
];
230 /* Not there, access error */
231 if (m
== output
->numUserModes
)
234 /* make sure the mode isn't active for this output */
235 if (output
->crtc
&& output
->crtc
->mode
== mode
)
238 memmove(output
->userModes
+ m
, output
->userModes
+ m
+ 1,
239 (output
->numUserModes
- m
- 1) * sizeof(RRModePtr
));
240 output
->numUserModes
--;
246 RROutputSetCrtcs(RROutputPtr output
, RRCrtcPtr
* crtcs
, int numCrtcs
)
251 if (numCrtcs
== output
->numCrtcs
) {
252 for (i
= 0; i
< numCrtcs
; i
++)
253 if (output
->crtcs
[i
] != crtcs
[i
])
259 newCrtcs
= malloc(numCrtcs
* sizeof(RRCrtcPtr
));
266 memcpy(newCrtcs
, crtcs
, numCrtcs
* sizeof(RRCrtcPtr
));
267 output
->crtcs
= newCrtcs
;
268 output
->numCrtcs
= numCrtcs
;
269 RROutputChanged(output
, TRUE
);
274 RROutputSetConnection(RROutputPtr output
, CARD8 connection
)
276 if (output
->connection
== connection
)
278 output
->connection
= connection
;
279 RROutputChanged(output
, TRUE
);
284 RROutputSetSubpixelOrder(RROutputPtr output
, int subpixelOrder
)
286 if (output
->subpixelOrder
== subpixelOrder
)
289 output
->subpixelOrder
= subpixelOrder
;
290 RROutputChanged(output
, FALSE
);
295 RROutputSetPhysicalSize(RROutputPtr output
, int mmWidth
, int mmHeight
)
297 if (output
->mmWidth
== mmWidth
&& output
->mmHeight
== mmHeight
)
299 output
->mmWidth
= mmWidth
;
300 output
->mmHeight
= mmHeight
;
301 RROutputChanged(output
, FALSE
);
306 RRDeliverOutputEvent(ClientPtr client
, WindowPtr pWin
, RROutputPtr output
)
308 ScreenPtr pScreen
= pWin
->drawable
.pScreen
;
311 RRCrtcPtr crtc
= output
->crtc
;
312 RRModePtr mode
= crtc
? crtc
->mode
: NULL
;
314 xRROutputChangeNotifyEvent oe
= {
315 .type
= RRNotify
+ RREventBase
,
316 .subCode
= RRNotify_OutputChange
,
317 .timestamp
= pScrPriv
->lastSetTime
.milliseconds
,
318 .configTimestamp
= pScrPriv
->lastConfigTime
.milliseconds
,
319 .window
= pWin
->drawable
.id
,
320 .output
= output
->id
,
321 .crtc
= crtc
? crtc
->id
: None
,
322 .mode
= mode
? mode
->mode
.id
: None
,
323 .rotation
= crtc
? crtc
->rotation
: RR_Rotate_0
,
324 .connection
= output
->connection
,
325 .subpixelOrder
= output
->subpixelOrder
327 WriteEventsToClient(client
, 1, (xEvent
*) &oe
);
331 * Destroy a Output at shutdown
334 RROutputDestroy(RROutputPtr output
)
336 FreeResource(output
->id
, 0);
340 RROutputDestroyResource(pointer value
, XID pid
)
342 RROutputPtr output
= (RROutputPtr
) value
;
343 ScreenPtr pScreen
= output
->pScreen
;
350 if (pScrPriv
->primaryOutput
== output
)
351 pScrPriv
->primaryOutput
= NULL
;
353 for (i
= 0; i
< pScrPriv
->numOutputs
; i
++) {
354 if (pScrPriv
->outputs
[i
] == output
) {
355 memmove(pScrPriv
->outputs
+ i
, pScrPriv
->outputs
+ i
+ 1,
356 (pScrPriv
->numOutputs
- (i
+ 1)) * sizeof(RROutputPtr
));
357 --pScrPriv
->numOutputs
;
362 RRResourcesChanged(pScreen
);
365 for (m
= 0; m
< output
->numModes
; m
++)
366 RRModeDestroy(output
->modes
[m
]);
370 for (m
= 0; m
< output
->numUserModes
; m
++)
371 RRModeDestroy(output
->userModes
[m
]);
372 free(output
->userModes
);
375 free(output
->clones
);
376 RRDeleteAllOutputProperties(output
);
382 * Initialize output type
387 RROutputType
= CreateNewResourceType(RROutputDestroyResource
, "OUTPUT");
395 * Initialize output type error value
398 RROutputInitErrorValue(void)
400 SetResourceTypeErrorValue(RROutputType
, RRErrorBase
+ BadRROutput
);
403 #define OutputInfoExtra (SIZEOF(xRRGetOutputInfoReply) - 32)
406 ProcRRGetOutputInfo(ClientPtr client
)
408 REQUEST(xRRGetOutputInfoReq
);
409 xRRGetOutputInfoReply rep
;
412 unsigned long extraLen
;
414 rrScrPrivPtr pScrPriv
;
421 REQUEST_SIZE_MATCH(xRRGetOutputInfoReq
);
422 VERIFY_RR_OUTPUT(stuff
->output
, output
, DixReadAccess
);
424 pScreen
= output
->pScreen
;
425 pScrPriv
= rrGetScrPriv(pScreen
);
427 rep
= (xRRGetOutputInfoReply
) {
429 .status
= RRSetConfigSuccess
,
430 .sequenceNumber
= client
->sequence
,
431 .length
= bytes_to_int32(OutputInfoExtra
),
432 .timestamp
= pScrPriv
->lastSetTime
.milliseconds
,
433 .crtc
= output
->crtc
? output
->crtc
->id
: None
,
434 .mmWidth
= output
->mmWidth
,
435 .mmHeight
= output
->mmHeight
,
436 .connection
= output
->connection
,
437 .subpixelOrder
= output
->subpixelOrder
,
438 .nCrtcs
= output
->numCrtcs
,
439 .nModes
= output
->numModes
+ output
->numUserModes
,
440 .nPreferred
= output
->numPreferred
,
441 .nClones
= output
->numClones
,
442 .nameLength
= output
->nameLength
444 extraLen
= ((output
->numCrtcs
+
445 output
->numModes
+ output
->numUserModes
+
446 output
->numClones
+ bytes_to_int32(rep
.nameLength
)) << 2);
449 rep
.length
+= bytes_to_int32(extraLen
);
450 extra
= malloc(extraLen
);
457 crtcs
= (RRCrtc
*) extra
;
458 modes
= (RRMode
*) (crtcs
+ output
->numCrtcs
);
459 clones
= (RROutput
*) (modes
+ output
->numModes
+ output
->numUserModes
);
460 name
= (char *) (clones
+ output
->numClones
);
462 for (i
= 0; i
< output
->numCrtcs
; i
++) {
463 crtcs
[i
] = output
->crtcs
[i
]->id
;
467 for (i
= 0; i
< output
->numModes
+ output
->numUserModes
; i
++) {
468 if (i
< output
->numModes
)
469 modes
[i
] = output
->modes
[i
]->mode
.id
;
471 modes
[i
] = output
->userModes
[i
- output
->numModes
]->mode
.id
;
475 for (i
= 0; i
< output
->numClones
; i
++) {
476 clones
[i
] = output
->clones
[i
]->id
;
480 memcpy(name
, output
->name
, output
->nameLength
);
481 if (client
->swapped
) {
482 swaps(&rep
.sequenceNumber
);
484 swapl(&rep
.timestamp
);
487 swapl(&rep
.mmHeight
);
491 swaps(&rep
.nameLength
);
493 WriteToClient(client
, sizeof(xRRGetOutputInfoReply
), &rep
);
495 WriteToClient(client
, extraLen
, extra
);
503 RRSetPrimaryOutput(ScreenPtr pScreen
, rrScrPrivPtr pScrPriv
, RROutputPtr output
)
505 if (pScrPriv
->primaryOutput
== output
)
508 /* clear the old primary */
509 if (pScrPriv
->primaryOutput
) {
510 RROutputChanged(pScrPriv
->primaryOutput
, 0);
511 pScrPriv
->primaryOutput
= NULL
;
514 /* set the new primary */
516 pScrPriv
->primaryOutput
= output
;
517 RROutputChanged(output
, 0);
520 pScrPriv
->layoutChanged
= TRUE
;
522 RRTellChanged(pScreen
);
526 ProcRRSetOutputPrimary(ClientPtr client
)
528 REQUEST(xRRSetOutputPrimaryReq
);
529 RROutputPtr output
= NULL
;
531 rrScrPrivPtr pScrPriv
;
534 REQUEST_SIZE_MATCH(xRRSetOutputPrimaryReq
);
536 ret
= dixLookupWindow(&pWin
, stuff
->window
, client
, DixGetAttrAccess
);
541 VERIFY_RR_OUTPUT(stuff
->output
, output
, DixReadAccess
);
543 if (output
->pScreen
!= pWin
->drawable
.pScreen
) {
544 client
->errorValue
= stuff
->window
;
549 pScrPriv
= rrGetScrPriv(pWin
->drawable
.pScreen
);
551 RRSetPrimaryOutput(pWin
->drawable
.pScreen
, pScrPriv
, output
);
557 ProcRRGetOutputPrimary(ClientPtr client
)
559 REQUEST(xRRGetOutputPrimaryReq
);
561 rrScrPrivPtr pScrPriv
;
562 xRRGetOutputPrimaryReply rep
;
563 RROutputPtr primary
= NULL
;
566 REQUEST_SIZE_MATCH(xRRGetOutputPrimaryReq
);
568 rc
= dixLookupWindow(&pWin
, stuff
->window
, client
, DixGetAttrAccess
);
572 pScrPriv
= rrGetScrPriv(pWin
->drawable
.pScreen
);
574 primary
= pScrPriv
->primaryOutput
;
576 rep
= (xRRGetOutputPrimaryReply
) {
578 .sequenceNumber
= client
->sequence
,
579 .output
= primary
? primary
->id
: None
582 if (client
->swapped
) {
583 swaps(&rep
.sequenceNumber
);
587 WriteToClient(client
, sizeof(xRRGetOutputPrimaryReply
), &rep
);